I have a small issue with Scheduled Notification on Android - Xamarin Forms Project. I want to schedule a daily notification at 17:00. It works ok on simulator but when I deploy it on a Samsung S7 Edge - Android 8.0, it notifies me at 17:00 and after I open the notification, it will keep notify every minute or so.
Here is my code, MainActivity.cs:
[Activity(Label = "SpiritMobile", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
static readonly string CHANNEL_ID = "location_notification";
internal static readonly string COUNT_KEY = "count";
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
CreateNotificationChannel();
Intent alarmIntent = new Intent(this, typeof(AlarmReceiver));
PendingIntent pending = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
AlarmManager alarmManager = GetSystemService(AlarmService).JavaCast<AlarmManager>();
var calendar = Calendar.Instance;
calendar.TimeZone = Java.Util.TimeZone.GetTimeZone("Europe/Bucharest");
calendar.Set(CalendarField.HourOfDay, 17);
calendar.Set(CalendarField.Minute, 00);
alarmManager.SetRepeating(AlarmType.RtcWakeup, calendar.TimeInMillis, AlarmManager.IntervalDay, pending);
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
ServicePointManager.ServerCertificateValidationCallback += (o, cert, chain, errors) => true;
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
void CreateNotificationChannel()
{
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
return;
}
var channel = new NotificationChannel(CHANNEL_ID, "reminders", NotificationImportance.Default)
{
Description = "reminder's channel"
};
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.CreateNotificationChannel(channel);
}
}
Then I have AlarmReceiver.cs:
[BroadcastReceiver]
public class AlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
var message = "Don't forget to submit your daily rates.";
Intent backIntent = new Intent(context, typeof(MainActivity));
backIntent.SetFlags(ActivityFlags.NewTask);
var resultIntent = new Intent(context, typeof(MainActivity));
PendingIntent pending = PendingIntent.GetActivities(context, 0,
new Intent[] { backIntent, resultIntent },
PendingIntentFlags.OneShot);
var builder = new NotificationCompat.Builder(context, "location_notification")
.SetAutoCancel(true)
.SetContentTitle("Submit your daily feeling!")
.SetContentText(message)
.SetSmallIcon(Resource.Drawable.icon);
builder.SetContentIntent(pending);
var notificationManager = NotificationManagerCompat.From(context);
notificationManager.Notify(1000, builder.Build());
}
}
Could you please tell me what is wrong here? What can be the cause of this?
You are setting your repeating alarm in OnCreate method of the Activity. So every time app is launched, a new alarm is registered with the AlarmManager. As it is repeating alarm you need to set it only once.
It can be achieved by checking if your alarm is already set.
Related
I am following the guide here however when I attempt to launch the notification in Xamarin forms Andriod, I get the following.
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/local-notifications
INotificationManager notificationManager;
int notificationNumber = 0;
notificationManager = DependencyService.Get<INotificationManager>();
notificationManager.NotificationReceived += (sender, eventArgs) =>
{
var evtData = (NotificationEventArgs)eventArgs;
ShowNotification(evtData.Title, evtData.Message);
};
void ShowNotification(string title, string message)
{
Device.BeginInvokeOnMainThread(() =>
{
var msg = new Label()
{
Text = $"Notification Received:\nTitle: {title}\nMessage: {message}"
};
stacklayout.Children.Add(msg);
});
}
My Main Activity
[Activity(Label = "THEHOCKEYLAB", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize, LaunchMode = LaunchMode.SingleTop )]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
CreateNotificationFromIntent(Intent);
Window.SetStatusBarColor(Android.Graphics.Color.Black); //here
}
protected override void OnNewIntent(Intent intent)
{
CreateNotificationFromIntent(intent);
}
void CreateNotificationFromIntent(Intent intent)
{
if (intent?.Extras != null)
{
string title = intent.GetStringExtra(AndroidNotificationManager.TitleKey);
string message = intent.GetStringExtra(AndroidNotificationManager.MessageKey);
DependencyService.Get<INotificationManager>().ReceiveNotification(title, message);
}
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
public interface INotificationManager
{
event EventHandler NotificationReceived;
void Initialize();
void SendNotification(string title, string message, DateTime? notifyTime = null);
void ReceiveNotification(string title, string message);
}
I get the following error.
System.NullReferenceException: 'Object reference not set to an
instance of an object.'
But I have had a look and cant find anything on it am using Xamarin forms version 5.0.0.2083
Its on this line am recieving the error.
notificationManager.NotificationReceived += (sender, eventArgs) =>
{
var evtData = (NotificationEventArgs)eventArgs;
ShowNotification(evtData.Title, evtData.Message);
};
Never mind I found my answer Credit to this SO. Like all Dependency's it must be registered or will always be null.
Android notification null pointer exception. This needs to be in ur main activity.cs.
DependencyService.Register<INotificationManager, AndroidNotificationManager>();
I'm using firebase to send push notifications from a server to my app, the message looks like this:
var message = new Message()
{
Notification = new Notification()
{
Title = "Title - Test",
Body = "Body - Test",
},
Token = registrationToken
};
The notification comes through to the device no problem. All I want from when the notification is clicked, is for the app to start if the app is closed (this works) and for the app to resume if it's in the background.
When it's in the background and I click the notification, I just get a white screen. The issue seems to go away when I remove my splash screen, however that is not an ideal solution...Here is the relevant code, what am I doing wrong?
SPLASH ACTIVITY:
[Activity(Label = "MyApp",
Theme = "#style/splashscreen",
MainLauncher = true,
NoHistory = true)]
public class SplashActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
}
protected override void OnResume()
{
base.OnResume();
var mainActivityIntent = new Intent(this, typeof(MainActivity));
mainActivityIntent.AddFlags(ActivityFlags.SingleTop | ActivityFlags.NoAnimation);
StartActivity(mainActivityIntent);
this.Finish();
}
public override void OnBackPressed() { }
}
MAIN ACTIVITY:
[Activity(Label = "MyApp",
Theme = "#style/MainTheme",
LaunchMode = LaunchMode.SingleTop,
MainLauncher = false,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation, ScreenOrientation = ScreenOrientation.FullSensor)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity MainActivityInstance { get; private set; }
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
this.Window.SetFlags(WindowManagerFlags.KeepScreenOn, WindowManagerFlags.KeepScreenOn);
this.Window.SetSoftInputMode(SoftInput.AdjustPan);
Forms.Init(this, savedInstanceState);
MainActivityInstance = this;
LoadApplication(new App());
}
Try changing MainLauncher = true for the main activity.
Adding ActivityFlags.ClearTop to mainActivityIntent.AddFlags() in my OnResume method on
SplashActivity has seemed to have worked:
protected override void OnResume()
{
base.OnResume();
var mainActivityIntent = new Intent(this, typeof(MainActivity));
mainActivityIntent.AddFlags(ActivityFlags.NoAnimation | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
StartActivity(mainActivityIntent);
this.Finish();
}
I have two activities: MainActivity and Activity2:
public class MainActivity : AppCompatActivity
{
DateTime time = DateTime.Now;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
SetContentView(Resource.Layout.activity_main);
var button = FindViewById<Button>(Resource.Id.button);
button.Text = "Button created at " + time.ToString();
button.Click += (s, e) =>
{
Intent intent = new Intent(this, typeof(Activity2));
StartActivity(intent);
};
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
and:
[Activity(Label = "Activity2")]
public class Activity2 : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity2);
Button button_close = FindViewById<Button>(Resource.Id.button_close);
button_close.Click += (s, e) =>
{
Intent intent = new Intent(this, typeof(MainActivity));
StartActivity(intent);
};
}
}
Clicking on button opens Activity2 and hides MainActivity. button_close closes Activity2 and opens a new instance of MainActivity. But I do not want a new instance to be created. How can I revive exactly the original previously-created instance of MainActivity and return to it after Activity2 is closed?
Here, button.Text shows whether a new instance of MainActivity is created.
Just call Finish() on Activity2, it will return to the previous.
If you want to pass some kind of result, you can use StartActivityForResult and in OnActivityResult get the resulting data.
At first I should say that I have read all similar questions and they can not solve my problem .
I have a Splash Screen in my Xamarin Forms project and check the credentials in it and then in each condition start Main Activity with different parameter toward the condition . When Splash Screen finish it's work and disappear , the app show a black screen about 10 seconds and then main page is showing
this is my Splash :
[Activity(Theme = "#style/MainTheme.Splash",
MainLauncher = true,
NoHistory = true,
ScreenOrientation = ScreenOrientation.Portrait)]
public class SplashActivity : Activity
{
static readonly string TAG = "X:" + typeof(SplashActivity).Name;
public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
{
base.OnCreate(savedInstanceState, persistentState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
Log.Debug(TAG, "SplashActivity.OnCreate");
}
protected override void OnResume()
{
base.OnResume();
Task startupWork = new Task(() => { SimulateStartup(); });
startupWork.Start();
}
async void SimulateStartup()
{
Some Code ...
InvokeMainActivity("SomeType");
}
private void InvokeMainActivity(string type)
{
Intent _activity = new Intent(Application.Context, typeof(MainActivity));
_activity.PutExtra("Key", type);
_activity.AddFlags(ActivityFlags.NoAnimation);
StartActivity(_activity);
}
and this is my MainActivity :
[Activity(Label = "#string/app_name",
Icon = "#drawable/icon",
Theme = "#style/MainTheme",
MainLauncher = false,
LaunchMode = LaunchMode.SingleTask,
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.Locale | ConfigChanges.LayoutDirection)
]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override async void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
Xamarin.Essentials.Platform.Init(this, bundle);
Rg.Plugins.Popup.Popup.Init(this, bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
FFImageLoading.Forms.Platform.CachedImageRenderer.Init(enableFastRenderer: true);
Window.DecorView.LayoutDirection = LayoutDirection.Rtl;
string type = Intent.GetStringExtra("SomeType");
LoadApplication(new App(type));
}
}
How can I fix this ?
Thanks to #LeonLu-MSFT I add this code in style.xml without any change in MainActivity and Spalsh Screen
<item name="android:windowIsTranslucent">true</item>
I don't have Mac and ios device to test in ios
I was also facing similar problem. I fixed it by adding
<item name="android:windowIsTranslucent">true</item>
in ~\Resources\values\styles.xml.
So if you are facing similar problem add it as per below screen shot and hopefully it will also work for you:
I'm having some troubles with location, i've followed one signal document but as you can see in the SS, location point still null
And here is some code (following the order, MainActivity.cs in .Android and App.cs in PCL)
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
PullToRefreshLayoutRenderer.Init();
OneSignal.Current.StartInit("onesignalID").EndInit();
OneSignal.Current.PromptLocation();
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
App.Current.On<Xamarin.Forms.PlatformConfiguration.Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
public App()
{
InitializeComponent();
var config = RealmConfiguration.DefaultConfiguration;
config.SchemaVersion = 1;
OneSignal.Current.StartInit("onesignalID").InFocusDisplaying(OSInFocusDisplayOption.None).HandleNotificationReceived(HandleNotificationReceived).HandleNotificationOpened(HandleNotificationOpened).EndInit();
OneSignal.Current.PromptLocation();
MainPage = new MainPage();
}
protected override void OnStart()
{
OneSignal.Current.RegisterForPushNotifications();
// Handle when your app starts
}
The location request is prompting in app init as expected but even if i allow location sharing, location point in onesignal still null