We have developed a Android App using Xamarin and we are facing problem in Azure Notification Hub. We were trying to send push notifications to Android devices registered in our Azure Mobile Service and no registered android devices are receiving the notifications. When we tried to debug it via Notification Hub in Azure Portal, the results are showing that the notifications are sent to the devices. However, the devices are not receiving the notifications which was receiving before.
Kindly let us know either we are missing something in our code (Find the code below) or is there any problem in Azure Notification Hub (for Android GCM).
Note: All the android permissions for push notifications are given in the same code file below and not in the Android manifest.
Our GCM Service Code Below:
using System.Text;
using Android.App;
using Android.Content;
using Android.Util;
using Gcm.Client;
//VERY VERY VERY IMPORTANT NOTE!!!!
// Your package name MUST NOT start with an uppercase letter.
// Android does not allow permissions to start with an upper case letter
// If it does you will get a very cryptic error in logcat and it will not be obvious why you are crying!
// So please, for the love of all that is kind on this earth, use a LOWERCASE first letter in your Package Name!!!!
using ByteSmith.WindowsAzure.Messaging;
using System.Diagnostics;
using System.Collections.Generic;
using System;
[assembly: Permission(Name = "#PACKAGE_NAME#.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "#PACKAGE_NAME#.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
//GET_ACCOUNTS is only needed for android versions 4.0.3 and below
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
namespace seeMuscatAndroidApp
{
//You must subclass this!
[BroadcastReceiver(Permission= Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE }, Categories = new string[] { "#PACKAGE_NAME#" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK }, Categories = new string[] { "#PACKAGE_NAME#" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY }, Categories = new string[] { "#PACKAGE_NAME#" })]
public class PushHandlerBroadcastReceiver : GcmBroadcastReceiverBase<GcmService>
{
public static string[] SENDER_IDS = new string[] { Constants.SenderID };
public const string TAG = "GoogleCloudMessaging";
}
[Service] //Must use the service tag
public class GcmService : GcmServiceBase
{
public static string RegistrationID { get; private set; }
private NotificationHub Hub { get; set; }
Context _generalContext;
public GcmService() : base(PushHandlerBroadcastReceiver.SENDER_IDS)
{
Log.Info(PushHandlerBroadcastReceiver.TAG, "GcmService() constructor");
}
protected override async void OnRegistered (Context context, string registrationId)
{
Log.Verbose(PushHandlerBroadcastReceiver.TAG, "GCM Registered: " + registrationId);
RegistrationID = registrationId;
_generalContext = context;
//createNotification("GcmService Registered...", "The device has been Registered, Tap to View!");
Hub = new NotificationHub(Constants.NotificationHubPath, Constants.ConnectionString);
try
{
await Hub.UnregisterAllAsync(registrationId);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
Debugger.Break();
}
var tags = new List<string>() { main.userCountry, main.userCity, main.userLatitude, main.userLongitude, main.userPhoneMake, main.userPhoneModel, main.userPhoneName, main.userPhoneAndroidVersion, main.userAppVersion,main.userUID};
Console.WriteLine("///////////HUB TAGS///////////////////");
Console.WriteLine("Country:" + main.userCountry);
Console.WriteLine("City:" + main.userCity);
Console.WriteLine("Latitude:" + main.userLatitude);
Console.WriteLine("Longitude:"+main.userLongitude);
Console.WriteLine("Make:" + main.userPhoneMake);
Console.WriteLine("Model:" + main.userPhoneModel);
Console.WriteLine("Phone Name:" + main.userPhoneName);
Console.WriteLine("Android Version:" + main.userPhoneAndroidVersion);
Console.WriteLine("App version:" + main.userAppVersion);
Console.WriteLine("User ID:" + main.userUID);
Console.WriteLine("///////////END OF HUB TAGS///////////////////");
try
{
var hubRegistration = await Hub.RegisterNativeAsync(registrationId, tags);
Debug.WriteLine("RegistrationId:" + hubRegistration.RegistrationId);
}
catch (Exception ex)
{
Debug.WriteLine("#########$$$$Error:"+ex.Message);
}
}
protected override void OnUnRegistered (Context context, string registrationId)
{
Log.Verbose(PushHandlerBroadcastReceiver.TAG, "GCM Unregistered: " + registrationId);
//Remove from the web service
// var wc = new WebClient();
// var result = wc.UploadString("http://your.server.com/api/unregister/", "POST",
// "{ 'registrationId' : '" + lastRegistrationId + "' }");
//createNotification("GcmService Unregistered...", "The device has been unregistered, Tap to View!");
}
protected override void OnMessage (Context context, Intent intent)
{
Log.Info(PushHandlerBroadcastReceiver.TAG, "GCM Message Received!");
Debug.WriteLine("/********* GCM Received ****************");
var msg = new StringBuilder();
if (intent != null && intent.Extras != null)
{
foreach (var key in intent.Extras.KeySet())
msg.AppendLine(key + "=" + intent.Extras.Get(key).ToString());
}
//Store the message
var prefs = GetSharedPreferences(context.PackageName, FileCreationMode.Private);
var edit = prefs.Edit();
edit.PutString("last_msg", msg.ToString());
edit.Commit();
string message = intent.Extras.GetString("message");
if (!string.IsNullOrEmpty(message))
{
createNotification("New todo item!", "Todo item: " + message);
return;
}
string msg2 = intent.Extras.GetString("msg");
string notititle = intent.Extras.GetString("notititle");
if (!string.IsNullOrEmpty(msg2))
{
createNotification(notititle, msg2);
return;
}
// createNotification("PushSharp-GCM Msg Rec'd", "Message Received for C2DM-Sharp... Tap to View!");
//createNotification("Unknown message details", msg.ToString());
}
protected override bool OnRecoverableError (Context context, string errorId)
{
Log.Warn(PushHandlerBroadcastReceiver.TAG, "Recoverable Error: " + errorId);
return base.OnRecoverableError (context, errorId);
}
protected override void OnError (Context context, string errorId)
{
Log.Error(PushHandlerBroadcastReceiver.TAG, "GCM Error: " + errorId);
}
void createNotification(string title, string desc)
{
//Create notification
var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
//Create an intent to show ui
Intent uiIntent = new Intent();
uiIntent.SetClass(this, typeof(dealsview));
uiIntent.PutExtra("contentID", "todaydeals");
uiIntent.PutExtra("contentName", "");
uiIntent.PutExtra("isSale", "");
//Create the notification
var notification = new Notification(Resource.Drawable.Icon, title);
//Auto cancel will remove the notification once the user touches it
notification.Flags = NotificationFlags.AutoCancel;
notification.Defaults = NotificationDefaults.All;
//Set the notification info
//we use the pending intent, passing our ui intent over which will get called
//when the notification is tapped.
notification.SetLatestEventInfo(this, title, desc, PendingIntent.GetActivity(this, 0, uiIntent, 0));
//Show the notification
notificationManager.Notify(1, notification);
}
}
}
Permission are tags in the Manifest file that has XML data. While compiling DVM checks the Manifest file for permissions and other necessary data to package in the .apk. You should always follow the same format.
Please have a look at this tutorial for more information.
Related
Receiving and opening notifications with the app in the background increments the number of Data sent.
In addition the notification is not showing when the app is killed or when it is in the foreground.
Below is my code, the source code is from Gerald Versluis https://github.com/jfversluis/XFFCMPushNotificationsSample
using System;
using Xamarin.Forms;
using Plugin.FirebasePushNotification;
using Xamarin.Forms.Xaml;
namespace FCMTest
{
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
CrossFirebasePushNotification.Current.Subscribe("all");
CrossFirebasePushNotification.Current.OnTokenRefresh += Current_OnTokenRefresh;
CrossFirebasePushNotification.Current.OnNotificationReceived += Current_OnNotificationReceived;
CrossFirebasePushNotification.Current.OnNotificationOpened += Current_OnNotificationOpened;
//CrossFirebasePushNotification.Current.OnNotificationAction += Current_OnNotificationAction;
}
private void Current_OnTokenRefresh(object source, FirebasePushNotificationTokenEventArgs e)
{
System.Diagnostics.Debug.WriteLine($"Token from function OnTokenRefresh: {e.Token}");
}
private void Current_OnNotificationReceived(object source, FirebasePushNotificationDataEventArgs d)
{
System.Diagnostics.Debug.WriteLine("Received");
foreach (var data in d.Data)
{
System.Diagnostics.Debug.WriteLine($"{data.Key} : {data.Value}");
}
}
/*private void Current_OnNotificationAction(object source, FirebasePushNotificationResponseEventArgs d)
{
System.Diagnostics.Debug.WriteLine("Opened");
foreach (var data in d.Data)
{
System.Diagnostics.Debug.WriteLine($"{data.Key} : {data.Value}");
}
}*/
private void Current_OnNotificationOpened(object source, FirebasePushNotificationResponseEventArgs d)
{
System.Diagnostics.Debug.WriteLine("Opened");
foreach (var data in d.Data)
{
System.Diagnostics.Debug.WriteLine($"{data.Key} : {data.Value}");
}
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
}
}
using FirebaseAdmin;
using FirebaseAdmin.Messaging;
using Google.Apis.Auth.OAuth2;
using System;
using System.Collections.Generic;
namespace FCMDispatcher
{
class Program
{
static void Main(string[] args)
{
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile("fcm-test-98fe5-firebase-adminsdk-oknwc-c290af4ff0.json")
});
// This registration token comes from the client FCM SDKs.
var registrationToken = "d8yECxIhJXQ:APA91bFGXSrnUVcP07TlN4HpvfstWwEdPQaj4wr6Z3Q-7JqcJJjrFy9LkWdlfzcCNDrZeVy55IDTWxvp5Gfyv8318uRRmIPo6Gp2IQnyUDSHqGLdTF8RMmlwyaECTKWDnmhClMLV8In9";
// See documentation on defining a message payload.
var message = new Message()
{
Data = new Dictionary<string, string>()
{
{"myData", "One more try to say Succeded!"},
},
Token = registrationToken,
//Topic = "all",
Notification = new Notification()
{
Title = "Test from code",
Body = "Here is your test!"
}
};
// Send a message to the device corresponding to the provided
// registration token.
string response = FirebaseMessaging.DefaultInstance.SendAsync(message).Result;
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);
}
}
}
Try adding priority with high or max to your Data Payload.
Data = new Dictionary<string, string>()
{
{"myData", "One more try to say Succeded!"},
{"priority", "high"},
},
This complex condition must match to show your notification:
https://github.com/CrossGeeks/FirebasePushNotificationPlugin/blob/d86266a9f45687b418f5f1e69c348681d1ff6e27/Plugin.FirebasePushNotification/DefaultPushNotificationHandler.android.cs#L151
This is going to be a long post! (grab a cup of coffee/popcorn)
I am using AltBeacon Xamarin sample in my code to show the beacons.
I have come across this example in creating Notifications in Xamarin.
Here there's an Application class where the core logic goes.
public class AltBeaconSampleApplication : Application, IBootstrapNotifier
{
private const string TAG = "AltBeaconSampleApplication";
BeaconManager _beaconManager;
private RegionBootstrap regionBootstrap;
private Region _backgroundRegion;
private BackgroundPowerSaver backgroundPowerSaver;
private bool haveDetectedBeaconsSinceBoot = false;
private string nearbyMessageString = "A beacon is nearby.";
private string nearbyTitleString = "AltBeacon Reference Application";
private MainActivity mainActivity = null;
public MainActivity MainActivity
{
get { return mainActivity; }
set { mainActivity = value; }
}
private NotificationActivity notificationActivity = null;
public NotificationActivity NotificationActivity
{
get { return notificationActivity; }
set { notificationActivity = value; }
}
public AltBeaconSampleApplication() : base() { }
public AltBeaconSampleApplication(IntPtr javaReference, Android.Runtime.JniHandleOwnership transfer) : base(javaReference, transfer) { }
public override void OnCreate()
{
base.OnCreate();
_beaconManager = BeaconManager.GetInstanceForApplication(this);
var iBeaconParser = new BeaconParser();
// Estimote > 2013
iBeaconParser.SetBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24");
_beaconManager.BeaconParsers.Add(iBeaconParser);
Log.Debug(TAG, "setting up background monitoring for beacons and power saving");
// wake up the app when a beacon is seen
_backgroundRegion = new Region("backgroundRegion", null, null, null);
regionBootstrap = new RegionBootstrap(this, _backgroundRegion);
// simply constructing this class and holding a reference to it in your custom Application
// class will automatically cause the BeaconLibrary to save battery whenever the application
// is not visible. This reduces bluetooth power usage by about 60%
backgroundPowerSaver = new BackgroundPowerSaver(this);
PerformHttpRequest();
}
public void DidDetermineStateForRegion(int state, AltBeaconOrg.BoundBeacon.Region region)
{
}
public async void PerformHttpRequest()
{
try
{
using (var client = new HttpClient())
{
var uri = "http://exampleuri";
var result = await client.GetStringAsync(uri);
var response = JsonConvert.DeserializeObject<BeaconURL>(result);
SendNotificationFromBeacon(response);
}
}
catch(Exception ex)
{
throw ex;
}
}
private void SendNotificationFromBeacon(BeaconURL receivedNotification)
{
// Setup an intent for SecondActivity:
Intent notificationIntent = new Intent(this, typeof(NotificationActivity));
// Pass some information to SecondActivity:
notificationIntent.PutExtra("CompaignUrl", receivedNotification.CompaignUrl);
notificationIntent.PutExtra("MediaUrl", receivedNotification.MediaUrl);
notificationIntent.PutExtra("titleText", receivedNotification.Title);
notificationIntent.SetFlags(ActivityFlags.NewTask);
// Create a task stack builder to manage the back stack:
Android.App.TaskStackBuilder stackBuilder = Android.App.TaskStackBuilder.Create(this);
// Add all parents of SecondActivity to the stack:
stackBuilder.AddParentStack(Java.Lang.Class.FromType(typeof(NotificationActivity)));
// Push the intent that starts SecondActivity onto the stack:
stackBuilder.AddNextIntent(notificationIntent);
// Obtain the PendingIntent for launching the task constructed by
// stackbuilder. The pending intent can be used only once (one shot):
const int pendingIntentId = 0;
PendingIntent pendingIntent =
stackBuilder.GetPendingIntent(pendingIntentId, PendingIntentFlags.OneShot);
// Instantiate the builder and set notification elements, including
// the pending intent:
var builder =
new NotificationCompat.Builder(this)
.SetContentTitle(receivedNotification.Title)
.SetContentText(receivedNotification.Text)
.SetSmallIcon(Android.Resource.Drawable.IcDialogInfo);
// Build the notification:
Notification notification = builder.Build();
// Get the notification manager:
NotificationManager notificationManager =
GetSystemService(Context.NotificationService) as NotificationManager;
// Publish the notification:
const int notificationId = 0;
notificationManager.Notify(notificationId, notification);
}
}
BeaconURL is a POCO class
NotificationActivity is a basic Activity class.
I perform the HttpClient request and get data. I create a notification and present it on my screen. It goes like this
Now when I tap on the notification, I dont go to the NotificationActivity. I am trying to invoke an activity from an ApplicationClass. Is this the right way to perform such stuff. Kindly provide details.
Thanks.
Edit: Added NotificationActivity Class
[Activity(Label = "NotificationActivity")]
public class NotificationActivity : MainActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
SetContentView(Resource.Layout.NotificationLayout);
TextView titleTextView = FindViewById<TextView>(Resource.Id.txtTitle);
titleTextView.Text = Intent.Extras.GetString("titleText", "");
ImageView mediaImage = FindViewById<ImageView>(Resource.Id.imgViewMedia);
mediaImage.SetImageBitmap(GetImageBitmapFromUrl(Intent.Extras.GetString("MediaUrl", "")));
}
private Bitmap GetImageBitmapFromUrl(string url)
{
Bitmap imageBitmap = null;
using (var webClient = new WebClient())
{
var imageBytes = webClient.DownloadData(url);
if (imageBytes != null && imageBytes.Length > 0)
{
imageBitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length);
}
}
return imageBitmap;
}
}
First thing you need to do is to set the your pending intent within the notification builder, it will get your NotificationActivity launching:
var builder =
new NotificationCompat.Builder(this)
.SetContentTitle("receivedNotification.Title")
.SetContentText("receivedNotification.Text")
.SetSmallIcon(Android.Resource.Drawable.IcDialogInfo)
.SetContentIntent(pendingIntent);
The second will be to get your back stack setup, from what you posted I'm not sure what the flow should be as the user will exit the app if they use the back button.
If you want the user to go back to the MainActivity when that press the back button, then you can add a ParentActivity to your NotificationActivity activity attribute, i.e.:
[Activity(Label = "NotificationActivity", ParentActivity = typeof(MainActivity))]
And thus the line:
stackBuilder.AddParentStack(Java.Lang.Class.FromType(typeof(NotificationActivity)));
Would add the MainActivity to the back stack.
I am trying to implement media/rich/enhanced notifications in ios. I have an iPhone 6, 6s and 7. The image I send in the payload appears in the rich notification on the 6 , but not on the 6s or 7. The code seems to just stop at the CreateDownloadTask (I have verified that I can change the Body text just before that line of code, but I can’t after). I have even had simpler version of this use NSData.FromUrl(url) but the code “breaks” at that line. The odd think is that it doesn’t truly break, it displays the text for the Body element that was originally pushed. Even a try catch doesn’t grab the error. FYI..category is there for the custom ui I am building. Can't figure out why it only works properly on iphone 6 (all the phone are on 10.2.x or above)
the payload is {"aps":{"alert":{"title":"title", "subtitle":"subtitle","body":"body"}, "category":"pushWithImage","mutable-content":1}, "pushImage":"https://ewcweb.azurewebsites.net/media/boldlythumb.png"}
I can’t send project but below is the service extension code:
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Foundation;
using SDWebImage;
using UIKit;
using UserNotifications;
namespace notifications
{
[Register ("NotificationService")]
public class NotificationService : UNNotificationServiceExtension
{
UNMutableNotificationContent BestAttemptContent { get; set; }
public Action ContentHandler { get; set; }
const string ATTACHMENT_IMAGE_KEY = "pushImage";
const string ATTACHMENT_FILE_NAME = "-attachment-image.";
protected NotificationService (IntPtr handle) : base (handle)
{
// Note: this .ctor should not contain any initialization logic.
}
public async Task<byte[]> LoadImage (string imageUrl)
{
var httpClient = new HttpClient ();
var contentsTask = await httpClient.GetByteArrayAsync (imageUrl);
return contentsTask;
}
public override void DidReceiveNotificationRequest (UNNotificationRequest request, Action<UNNotificationContent> contentHandler)
{
string imageURL = null;
ContentHandler = contentHandler;
BestAttemptContent = request.Content.MutableCopy () as UNMutableNotificationContent;
if (BestAttemptContent != null) {
if (BestAttemptContent.UserInfo.ContainsKey (new NSString (ATTACHMENT_IMAGE_KEY))) {
imageURL = BestAttemptContent.UserInfo.ValueForKey (new NSString (ATTACHMENT_IMAGE_KEY)).ToString ();
}
if (imageURL == null) {
ContentHandler (BestAttemptContent);
return;
}
var url = new NSUrl (imageURL.ToString ());
NSError err = null;
var task = NSUrlSession.SharedSession.CreateDownloadTask ( new NSMutableUrlRequest (url),(tempfile, response, error) => {
if (error != null)
{
ContentHandler (BestAttemptContent);
return;
}
if (tempfile == null)
{
ContentHandler (BestAttemptContent);
return;
}
var cache = NSSearchPath.GetDirectories (NSSearchPathDirectory.CachesDirectory, NSSearchPathDomain.User, true);
var cachesFolder = cache [0];
var guid = NSProcessInfo.ProcessInfo.GloballyUniqueString;
var fileName = guid + ".png";
var cacheFile = cachesFolder + "/" + fileName;
var attachmentURL = NSUrl.CreateFileUrl (cacheFile, false, null);
NSFileManager.DefaultManager.Move(tempfile, attachmentURL, out err);
if (err != null)
{
ContentHandler (BestAttemptContent);
return;
}
// Create attachment;
var attachmentID = "image";
var options = new UNNotificationAttachmentOptions ();
var attachment = UNNotificationAttachment.FromIdentifier (attachmentID, attachmentURL, options, out err);
BestAttemptContent.Attachments = new UNNotificationAttachment [] { attachment };
BestAttemptContent.Title = BestAttemptContent.Title;
BestAttemptContent.Body = BestAttemptContent.Body;
BestAttemptContent.CategoryIdentifier = BestAttemptContent.CategoryIdentifier;
BestAttemptContent.Subtitle = BestAttemptContent.Subtitle;
//Display notification
ContentHandler (BestAttemptContent);
});
task.Resume ();
} else {
// Display notification
ContentHandler (BestAttemptContent);
}
}
public override void TimeWillExpire ()
{
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
ContentHandler (BestAttemptContent);
}
}
}
How to use Broadcast Reciever in Xamarin.Form reference to this forum http://forums.xamarin.com/discussion/7070/how-to-prevent-sms-going-to-inbox
the class
public class SmsReceiver : BroadcastReceiver
{
public static readonly string IntentAction = "android.provider.Telephony.SMS_RECEIVED";
public override void OnReceive(Context context, Intent intent)
{
InvokeAbortBroadcast();
try
{
if (intent.Action != IntentAction) return;
var bundle = intent.Extras;
if (bundle == null) return;
var pdus = bundle.Get("pdus");
var castedPdus = JNIEnv.GetArray<Java.Lang.Object>(pdus.Handle);
var msgs = new SmsMessage[castedPdus.Length];
var sb = new StringBuilder();
String sender = null;
for (var i = 0; i < msgs.Length; i++)
{
var bytes = new byte[JNIEnv.GetArrayLength(castedPdus[i].Handle)];
JNIEnv.CopyArray(castedPdus[i].Handle, bytes);
msgs[i] = SmsMessage.CreateFromPdu(bytes);
if (sender == null) sender = msgs[i].OriginatingAddress;
sb.Append(string.Format("SMS From: {0}{1}Body: {2}{1}", msgs[i].OriginatingAddress,
System.Environment.NewLine, msgs[i].MessageBody));
}
if (sender != null && sender.EndsWith("09068100820"))
{
// Process our sms...
// SMS.updateMessageBox("\nFrom: " + msg.getOriginatingAddress() + "\n" +
//"Message: " + msg.getMessageBody() + "\n");
/*((SMS) context).delete();*/
Toast.MakeText(context, "IsOrderedBroadcast :" + IsOrderedBroadcast.ToString() + "\n" + sb.ToString(), ToastLength.Long).Show();
}
else
{
ClearAbortBroadcast();
}
}
catch (Exception ex)
{
Toast.MakeText(context, ex.Message, ToastLength.Long).Show();
}
}
}
How to implement this class in Xamarin.Form and get the incoming SMS, Thanks in advance and Good Day :D
From Android 4.4, You can't do any kind of operation on SMS except just reading it if your app isn't the default SMS app.
If your app is default sms app and you want to block sender or whatever then put your SmsReceiver in Android Project and register it in Application class.
I don't think you need to do anything in Forms Project.
If I open the application by clicking on the notification (got from Google Cloud Messaging), I doesn't get splash-screen
GcmListenerService.cs
using Android.App;
using Android.Content;
using Android.OS;
using Android.Gms.Gcm;
using Android.Util;
using System;
using Android.Database.Sqlite;
namespace Dharma.Droid
{
[Service (Exported = false), IntentFilter (new [] { "com.google.android.c2dm.intent.RECEIVE" })]
public class MyGcmListenerService : GcmListenerService
{
public override void OnMessageReceived (string from, Bundle data)
{
var message = data.GetString ("message");
Log.Debug ("MyGcmListenerService", "From: " + from);
Log.Debug ("MyGcmListenerService", "Message: " + message);
DataAccess.InsertDowload (message);
SendNotification (message);
}
void SendNotification (string message)
{
var intent = new Intent (this, typeof(MainActivity));
intent.AddFlags (ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity (this, 0, intent, PendingIntentFlags.OneShot);
var notificationBuilder = new Notification.Builder (this)
.SetSmallIcon (Resource.Drawable.mhu2)
.SetContentTitle ("Mobile Health Unit")
.SetContentText ("U heeft een nieuwe vragenlijst.")
.SetAutoCancel (true)
.SetContentIntent (pendingIntent);
var notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
notificationManager.Notify (0, notificationBuilder.Build());
}
}
}
InstanceIdListenerService.cs
using Android.App;
using Android.Content;
using Android.Gms.Gcm.Iid;
namespace Dharma.Droid
{
[Service(Exported = false), IntentFilter(new[] { "com.google.android.gms.iid.InstanceID" })]
class MyInstanceIDListenerService : InstanceIDListenerService
{
public override void OnTokenRefresh()
{
var intent = new Intent (this, typeof (RegistrationIntentService));
StartService (intent);
}
}
}
RegistrationIntentService.cs
using System;
using Android.App;
using Android.Content;
using Android.Util;
using Android.Gms.Gcm;
using Android.Gms.Gcm.Iid;
namespace Dharma.Droid
{
[Service(Exported = false)]
class RegistrationIntentService : IntentService
{
static object locker = new object();
public RegistrationIntentService() : base("RegistrationIntentService") { }
protected override void OnHandleIntent (Intent intent)
{
try
{
Log.Info ("RegistrationIntentService", "Calling InstanceID.GetToken");
lock (locker)
{
var instanceID = InstanceID.GetInstance (this);
var token = instanceID.GetToken (
"***************", GoogleCloudMessaging.InstanceIdScope, null);
Log.Info ("RegistrationIntentService", "GCM Registration Token: " + token);
SendRegistrationToAppServer (token);
Subscribe (token);
}
}
catch (Exception e)
{
Log.Debug("RegistrationIntentService", "Failed to get a registration token");
return;
}
}
void SendRegistrationToAppServer (string token)
{
}
void Subscribe (string token)
{
var pubSub = GcmPubSub.GetInstance(this);
pubSub.Subscribe(token, "/topics/global", null);
}
}
}
SplashActivity.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V7.App;
using Android.Util;
using System.Threading.Tasks;
using Android.Gms.Common;
namespace Dharma.Droid
{
[Activity(Theme = "#style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
public class SplashActivity : AppCompatActivity
{
static readonly string TAG = "X:" + typeof (SplashActivity).Name;
public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
{
base.OnCreate(savedInstanceState, persistentState);
}
protected override void OnResume()
{
base.OnResume();
Task startupWork = new Task(() =>
{
Task.Delay(5000); // Simulate a bit of startup work.
});
startupWork.ContinueWith(t =>
{
NetworkDiscovery network = new NetworkDiscovery();
CredentialsService cs = new CredentialsService();
if (GetToken() && network.IsOnline())
{
StartActivity(typeof (MainActivity));
}
else
{
StartActivity(typeof (NoInternetActivity));
}
}, TaskScheduler.FromCurrentSynchronizationContext());
startupWork.Start();
}
public bool GetToken()
{
if (IsPlayServicesAvailable ())
{
var intent = new Intent (this, typeof (RegistrationIntentService));
StartService (intent);
return true;
}
else
{
return false;
}
}
public bool IsPlayServicesAvailable ()
{
int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable (this);
if (resultCode != ConnectionResult.Success)
{
return false;
}
else
{
return true;
}
}
}
}
The issue is with these lines:
var intent = new Intent (this, typeof(MainActivity));
intent.AddFlags (ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity (this, 0, intent, PendingIntentFlags.OneShot);
Specifically var intent = new Intent (this, typeof(MainActivity)); where you are telling the notification to open your MainActivity when it is clicked. If you want to show the splash screen, you should tell it to open the splash screen instead by replacing that line with:
var intent = new Intent (this, typeof(SplashActivity));
The only issue with this is if the application is already open, you might not want to show the splash screen again. To fix this, I would recommend doing something like this where they have a boolean on IsRunning that gets set in the MainActivity lifecycle events. You could check that boolean like this possibly:
Activity intent;
if(MainActivity.IsRunning) {
intent = new Intent (this, typeof(MainActivity));
intent.AddFlags (ActivityFlags.ClearTop);
} else {
intent = new Intent (this, typeof(SplashActivity));
intent.AddFlags (ActivityFlags.ClearTop);
}
var pendingIntent = PendingIntent.GetActivity (this, 0, intent, PendingIntentFlags.OneShot);
Warning, I did not test the code above.