Get reminders based on data in a database - xamarin

I want to get reminders for some Appointments that I have saved in database and they have a notificationTime property witch is the time when a notification needs to be displayed.
My approach so far is to write some kind of job that runs 1 or 2 times a day to pull the notifications that need to be registered in the next 24h and ofc register them (if you guys have a better ideea lmk :D )
This works BUT:
Only if the app is in foreground / background; then I get notification every 15min or so;
If I KILL the app I don't receive notification on my physical device (Xiaomi Redmi Note 9 Pro with Android version 12 SKQ),
only on the virtual one (Pixel 5 Android 13)
Right now I have a class that extends JobService and I use JobScheduler to schedule the Job to run every 15 min (for testing so I don't need to w8 12h xD )
Here is the JobScheduler witch I call in MainActivity file in OnCreate method
Console.WriteLine("Schedualing job");
TimeSpan interval = TimeSpan.FromMinutes(15);
var javaClass = Java.Lang.Class.FromType(typeof(NotificationService));
var componentName = new ComponentName(Application.Context, javaClass);
var jobInfo = new JobInfo.Builder(1, componentName)
.SetPeriodic(15 * 60 * 1000, 30 * 60 * 1000)
.SetRequiredNetworkType(NetworkType.Any)
.SetPersisted(true)
.Build();
var jobScheduler = (JobScheduler)GetSystemService(JobSchedulerService);
var resultCode = jobScheduler.Schedule(jobInfo);
and here is the NotificationService.cs
[Service(Name = "com.companyname.deratizare_mobile.NotificationService",
Permission = "android.permission.BIND_JOB_SERVICE")]
public class NotificationService : JobService
{
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
return StartCommandResult.StickyCompatibility;
}
public override bool OnStartJob(JobParameters #params)
{
Console.WriteLine("Job started");
Task.Run(async () =>
{
//var hasSuccessful = await ProccessNotificationToRegister();
var notification = new NotificationRequest
{
Title = "Job",
Description = $"Description",
Schedule = new NotificationRequestSchedule
{
NotifyTime = DateTime.Now,
}
};
LocalNotificationCenter.Current.Show(notification);
JobFinished(#params, false);
Console.WriteLine("Job finished");
});
return true;
}
public override bool OnStopJob(JobParameters #params)
{
Console.WriteLine("Job stopped");
return true;
}
}
AndroidManifest
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.BIND_JOB_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
UPDATE
I have given permission to auto start to my app from the device and it works
SOLUTION
I ended up using FCM and a hosted service on the server that checks the cache every 5 minutes where I have stored the next notification that needs to be displaied

You can try to use Firebase push notifications.
With push notifications, you can update your users without requiring the app to run at all times or having it poll a server, potentially running down the battery.
For more information, you can check Implementing Push Notifications in Your Android Apps and Firebase Cloud Messaging.

Related

Xamarin.UWP local notification not working

I have implemented a code to send Local Notifications for a particular date and time on Android and iOS platform.And, My code is working for Android and iOS platform.In Android,I am using AlarmManager.
and in iOS, UILocationNotification for sending notifications. But , I didn't find any solution for the UWP platform to implement the Local Notification feature
using Dependency Service as i got for Android and iOS platform. Is there any solution for sending local notifications for particular
date and time for all the platforms including "UWP"(mandatory) in Xamarin.forms????
Xamarin.UWP local notification not working
If you want to make Local notification fore Xamarin.Forms, please refer this document. But it has not implement UWP platform. So we need implement schedule notification within uwp and use dependency service to call it. And I have implement a simple you could refer.
interface
public interface INotificationManager
{
int ScheduleNotification(string title, string message,DateTime scheduledTime);
}
Implement
public class UWPNotificationManager : INotificationManager
{
int messageId = -1;
public int ScheduleNotification(string title, string message,DateTime scheduledTime)
{
messageId++;
string TOAST = $#"<toast>
<visual>
<binding template='ToastGeneric'>
<text>{title}</text>
<text>{message}</text>
</binding>
</visual>
<audio src =""ms-winsoundevent:Notification.Mail"" loop=""true""/>
</toast>";
Windows.Data.Xml.Dom.XmlDocument xml = new Windows.Data.Xml.Dom.XmlDocument();
xml.LoadXml(TOAST);
ScheduledToastNotification toast = new ScheduledToastNotification(xml, scheduledTime);
toast.Id = "IdTostone" + messageId.ToString();
toast.Tag = "NotificationOne";
toast.Group = nameof(UWPNotificationManager);
ToastNotificationManager.CreateToastNotifier().AddToSchedule(toast);
return messageId;
}
}
Usage
private void OnScheduleClick(object sender, EventArgs e)
{
notificationNumber++;
string title = $"Local Notification #{notificationNumber}";
string message = $"You have now received {notificationNumber} notifications!";
notificationManager.ScheduleNotification(title, message,DateTime.Now + TimeSpan.FromSeconds(3));
}
Try to use
ToastNotificationManager.CreateToastNotifier().Show(toast);

Xamarin Android Facebook AppInviteDialog not showing

I'm using the Xamarin.FacebookSdk to display the App Invite Dialog. For iOS everything works great but for Android, nothing displays.
Update
It turns out iOS isn't always working. I actually get the following error sometimes:
[0:] Invite Failed Error Domain=com.facebook.sdk.core Code=9 "(null)"
I can step through the following code until it gets to the AppInv.Show. However, Show never shows anything. I tried having the Facebook app installed and without it installed.
public class FacebookService : IFacebookService
{
public void InviteFriends(string appLinkUrl, string previewImageUrl)
{
if (AppInviteDialog.CanShow())
{
var activity = Xamarin.Forms.Forms.Context as Activity;
var content = new AppInviteContent.Builder().SetApplinkUrl(appLinkUrl).SetPreviewImageUrl(previewImageUrl).Build() as AppInviteContent;
//AppInviteDialog.Show(activity, content);
AppInviteDialog AppInv = new AppInviteDialog(activity);
var callbackManager = CallbackManagerFactory.Create();
var invitecallback = new CCallback();
AppInv.RegisterCallback(callbackManager, invitecallback);
AppInv.Show(content);
}
}
}
public class CCallback : Java.Lang.Object, IFacebookCallback
{
public void OnCancel()
{
System.Diagnostics.Debug.WriteLine($"Invite was cancelled");
}
public void OnError(FacebookException error)
{
System.Diagnostics.Debug.WriteLine($"Invite failed {error.Message}");
}
public void OnSuccess(Java.Lang.Object result)
{
System.Diagnostics.Debug.WriteLine($"Invite was a success: {result}");
}
}
I added the following to the AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
........
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="#string/app_id" />
<activity android:name="com.facebook.FacebookActivity" android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation" android:theme="#android:style/Theme.Translucent.NoTitleBar" android:label="#string/app_name" />
<provider android:authorities="com.facebook.app.FacebookContentProviderXXXXXMy App IdXXXX" android:name="com.facebook.FacebookContentProvider" android:exported="true" />
It turns out that AppInviteDialog was deprecated by Facebook.
It sure would have been nice for a more informative error to be displayed.

Push Notification using Amazon SNS – Device id

Developing the mobile app using the Xamarin Forms. For push notification we are using Amazon Simple Notification Service(SNS).
Xamarin.Andriod :
1. While installing the app we have used the below code snippet to register the device id into the Amazon SNS in OnCreate method of MainActivity. It works fine
using (Intent intent = new Intent("com.google.android.c2dm.intent.REGISTER"))
{
string senders = AmazonUtils.GoogleConsoleProjectId;
intent.SetPackage("com.google.android.gsf");
intent.PutExtra("app", PendingIntent.GetBroadcast(this, 0, new Intent(), 0));
intent.PutExtra("sender", senders);
this.StartService(intent);
}
Every time when app opens checking the corresponding device id is registered in the Amazon SNS. Due to this app takes additional 4 secs to check this process and after that page is loading.
Do we need to check the device is register or not for every time when the app opens ?. Is this standard for the push notification ?.
Regards,
Cheran
Install Xam.Plugins.Settings.
It will add a helper class called Settings
In this class you should add:
private const string IsRegisteredKey = "registered_key";
private static readonly bool IsRegisteredDefault = false;
//Then adding this property
public static bool IsRegistered
{
get
{
return AppSettings.GetValueOrDefault(IsRegisteredKey, IsRegisteredDefault);
}
set
{
AppSettings.AddOrUpdateValue(IsRegisteredKey, value);
}
}
Then in your code call this property, like this:
using YourProjectNameSpace.Droid.Helper
....
if(!Settings.IsRegistered)
{
using (Intent intent = new Intent("com.google.android.c2dm.intent.REGISTER"))
{
string senders = AmazonUtils.GoogleConsoleProjectId;
intent.SetPackage("com.google.android.gsf");
intent.PutExtra("app", PendingIntent.GetBroadcast(this, 0, new Intent(), 0));
intent.PutExtra("sender", senders);
this.StartService(intent);
}
Settings.IsRegistered = true;
}

Geo location is not working in xamarin android

I am try to get the current geo location of the phone using 'plugin.geolocator' but it works fine in ios in android getting task cancellation exception. Here is the code I have tried. Please suggest any idea why I am getting this exception.
sample code:
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = -1;
if (locator.IsGeolocationEnabled)
{
var position = await locator.GetPositionAsync(TimeSpan.FromMilliseconds(5000));
}
These are the permissions I have gave in android manifest file.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
I am getting task cancellation exception while I am testing in emulator. I have tried with changing time span but no luck getting task cancellation exception only.
Set a different value for Desired accuracy (big values -> more chance to have a result):
locator.DesiredAccuracy = 100;
Well, you also have to override OnRequestPermissionResult on your MainActivity class:
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
And ensure your Android Target version is API 25+. See https://jamesmontemagno.github.io/GeolocatorPlugin/GettingStarted.html

in-app billing connection issue

I am trying to connect the in-app-billing but the OnConnected event not being hit.
my Android Manifest code is
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="alphaTestApp.alphaTestApp" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="21" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:label="alphaTestApp" android:icon="#drawable/Icon"></application>
</manifest>
And the Main Activity file code is.
[Activity(Label = "alphaTestApp", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
private InAppBillingServiceConnection _serviceConnection;
string publicKey = "REDACTED";
private IList<Product> _products;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
_serviceConnection = new InAppBillingServiceConnection(this, publicKey);
if (_serviceConnection == null)
{
Toast t = Toast.MakeText(this, "Error while connecting", ToastLength.Long);
t.Show();
}
_serviceConnection.Connect();
Toast t1 = Toast.MakeText(this, "Connected app", ToastLength.Long);
t1.Show();
_serviceConnection.OnConnected += () =>
{
Toast t2 = Toast.MakeText(this, "Retrieving Items", ToastLength.Long);
t2.Show();
_products = _serviceConnection.BillingHandler.QueryInventoryAsync(new List<string> {
"goldcoin100"
}, ItemType.Product) as IList<Product>;
if (_products == null)
return;
_serviceConnection.BillingHandler.BuyProduct(_products[0]);
};
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += delegate
{
Toast t3 = Toast.MakeText(this, "Retrieving Items", ToastLength.Long);
t3.Show();
_products = _serviceConnection.BillingHandler.QueryInventoryAsync(new List<string> {
"goldcoin100"
}, ItemType.Product) as IList<Product>;
if (_products == null)
return;
_serviceConnection.BillingHandler.BuyProduct(_products[0]);
};
}
}
It's probably not the reason, but it would be best to set your OnConnected handler before you call Connect just in case it connects in less time than it takes for the Toast code to run.
Also, you should make the OnConnected handler async and then await on the call to QueryInventoryAsync (in a Lambda the async keyword goes before the brackets, e.g. OnConnected += async () => ...). As it is, QueryInventoryAsync will return a Task<IList<Product>> so trying to convert it using as IList<Product> will fail and _products will always be null.
If you're running on an emulator, make sure that you've got Google Play Services installed and up-to-date. There's an article on doing this for the Xamarin Android Player here: Installing Google Play Services in XAP. Although note that BuyProduct shouldn't work on an emulator using real products, you'll need to use the test product IDs (e.g. ReservedTestProductIDs.Purchased, and note that once you've purchased this one you'll need to call ConsumePurchase on it before you can purchase it again).
Also, don't post your API key on an open forum.

Resources