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>();
Related
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.
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.
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
I have this Xamarin Android App (not Forms) that opens a camera and lets me take a photo and go with it or take a new one. After that, ImageView shows me the pic on the app using a bitmap. I could not save to gallery using bitmap(I don't know how to, or if there is an easier way). I need the app to get the last picture taken with the application (The why of needing it to be saved) and send it to a server on the click of a button (I need some help on that bit as well). And that's all I need to do.
Here are the code MainActivity.cs:
using Android.App;
using Android.Widget;
using Android.OS;
using Android.Content;
using Android.Provider;
using Android.Runtime;
using Android.Graphics;
namespace CameraApp
{
[Activity(Label = "#string/app_name", Theme = "#style/AppTheme", MainLauncher = true)]
public class MainActivity : Activity
{
ImageView imageView;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.activity_main);
Button btnCamera = FindViewById<Button>(Resource.Id.btnCamera);
imageView = FindViewById<ImageView>(Resource.Id.imageView);
btnCamera.Click += BtnCamera_Click;
}
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
Bitmap bitmap = (Bitmap)data.Extras.Get("data");
imageView.SetImageBitmap(bitmap);
}
private void BtnCamera_Click(object sender, System.EventArgs e)
{
Intent intent = new Intent(MediaStore.ActionImageCapture);
StartActivityForResult(intent, 0);
}
}
}
I wrote a demo about your needs.I add the camera and external storeage permission and store the image to gallery, here is running GIF.
There is code of running demo.I add the runtime permission(camera and WriteExternalStorage) request.and judge situations when users did not take photo, then return back the app.
[Activity(Label = "#string/app_name", Theme = "#style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity, ActivityCompat.IOnRequestPermissionsResultCallback
{
Button button1;
ImageView imageView1;
View layout;
static readonly int REQUEST_CAMERA_WriteExternalStorage = 0;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
layout = FindViewById<RelativeLayout>(Resource.Id.sample_main_layout);
button1 = FindViewById<Button>(Resource.Id.button1);
imageView1 = FindViewById<ImageView>(Resource.Id.imageView1);
button1.Click += (o, e) =>
{
CheckPermission();
};
}
public void CheckPermission()
{
if ((ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) == (int)Permission.Granted)&& (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) == (int)Permission.Granted))
{
// Camera and store permission has been granted
ShowCamera();
}
else
{
// Camera and store permission has not been granted
RequestPermission();
}
}
private void RequestPermission()
{
ActivityCompat.RequestPermissions(this, new String[] { Manifest.Permission.Camera, Manifest.Permission.WriteExternalStorage }, REQUEST_CAMERA_WriteExternalStorage);
}
//get result of persmissions
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
if (requestCode == REQUEST_CAMERA_WriteExternalStorage)
{
if ( PermissionUtil.VerifyPermissions(grantResults))
{
// All required permissions have been granted, display Camera.
ShowCamera();
}
else
{
// permissions did not grant, push up a snackbar to notificate USERS
Snackbar.Make(layout, Resource.String.permissions_not_granted, Snackbar.LengthShort).Show();
}
}
else
{
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void ShowCamera()
{
Intent intent = new Intent(MediaStore.ActionImageCapture);
StartActivityForResult(intent, 0);
}
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
Bitmap bitmap=null;
//If user did not take a photeo , he will get result of bitmap, it is null
try {
bitmap = (Bitmap)data.Extras.Get("data");
} catch(Exception e)
{
Log.Error("TakePhotoDemo1", e.Message);
Toast.MakeText(this, "You did not take a photo", ToastLength.Short).Show();
}
if (bitmap != null)
{
MediaStore.Images.Media.InsertImage(ContentResolver, bitmap, "screen", "shot");
imageView1.SetImageBitmap(bitmap);
}
else
{
Toast.MakeText(this, "You did not take a photo", ToastLength.Short).Show();
}
}
}
PermissionUtil.cs Check that all given permissions have been granted by verifying that each entry in the given array is of the value Permission.Granted.
public abstract class PermissionUtil
{
public static bool VerifyPermissions(Permission[] grantResults)
{
// At least one result must be checked.
if (grantResults.Length < 1)
return false;
// Verify that each required permission has been granted, otherwise return false.
foreach (Permission result in grantResults)
{
if (result != Permission.Granted)
{
return false;
}
}
return true;
}
}
There is my code.
https://github.com/851265601/TakePhotoDemo1
The former code will add the image at the end of the gallery(MediaStore.Images.Media.InsertImage). If you want to modify the date so it appears at the beginning or any other metadata, see this link.
https://gist.github.com/samkirton/0242ba81d7ca00b475b9
You can insert the image through MediaStore
MediaStore.Images.Media.InsertImage(this, yourBitmap, yourTitle, yourDescription);
Note: You might wanna add the Write External Storage permission for this.