How to update badge count while app is open? - xamarin

I am using BottomNavigationBar plugin and it works fine.
My problem is I want to update badge count when notification is received while app is in running mode(i.e. open). I am using Setting Plugin for Xamarin and store count in that. On app initialize it display counts properly. But when my app is open I am changing value of Setting and immediately change the value of badge. How's that can be possible?

Where is several ways to do this.
First, if you are using Xamarin forms then you can use MessagingCenter. It is cross platform Event Bus implementation.
I used Xamarin.Form. Example for sending message
public MainPage()
{
InitializeComponent();
var count = 0;
_button.Clicked += (sender, args) =>
{
MessagingCenter.Send<MainPage, int>(this, "MyMessage", count++);
};
}
Example of reciever
public App()
{
InitializeComponent();
var mp = new MainPage();
MainPage = new MainPage();
MessagingCenter.Subscribe<MainPage, int>(this, "MyMessage", (sender, arg) => {
MainPage.DisplayAlert("MyMessage", $"Hit Count: {arg}", "ok");
});
}
There is more info and examples if you check Link
Second, add event to your settings class, and invoke it in your setter

Related

URI start of MAUI Windows app creates a new instance. I need to have only one instance of app

I am able to start my Windows MAUI app using an URI, and I can get the URI itself. But, it appears that a NEW instance of the app is being created. This is not ideal for me -- if my app is already running, I want to use that instance.
I have done something like this for a Xamarin.Forms app. I override OnActivated in Application class.
Re: my MAUI app, I'm not even clear on whether the issue is how I've done the "protocol" in package.appxmanifest, or if it is how I respond to lifecycle events.
The default behaviour is to run multiple instances of your app. You can make the app single-instanced by defining a customized class with a Main method as suggested in this blog post:
[STAThread]
static async Task Main(string[] args)
{
WinRT.ComWrappersSupport.InitializeComWrappers();
bool isRedirect = await DecideRedirection();
if (!isRedirect)
{
Microsoft.UI.Xaml.Application.Start((p) =>
{
var context = new DispatcherQueueSynchronizationContext(
DispatcherQueue.GetForCurrentThread());
SynchronizationContext.SetSynchronizationContext(context);
new App();
});
}
return 0;
}
private static async Task DecideRedirection()
{
bool isRedirect = false;
AppActivationArguments args = AppInstance.GetCurrent().GetActivatedEventArgs();
ExtendedActivationKind kind = args.Kind;
AppInstance keyInstance = AppInstance.FindOrRegisterForKey("randomKey");
if (keyInstance.IsCurrent)
{
keyInstance.Activated += OnActivated;
}
else
{
isRedirect = true;
await keyInstance.RedirectActivationToAsync(args);
}
return isRedirect;
}
There is an open suggestion to simplify this process available on GitHub.

Xamarin.Forms App return data to calling App

So, either I am asking incorrectly, or it isn't possible, let's see which...
If my app (Xamarin.Forms) is launched from another app, in order to get a url from my app, how do I return that data to the calling app? I wrongly assumed SetResult and Finish, I also wrongly assumed StartActivityForResult, but there has to be a way to do this. I know how to get data INTO my app from another app, but not the same in return.
POSSIBLE PARTIAL SOLUTION -- UPDATE, FAILS
So I have to setup an interface in my PCL, and call the method from the listview item selected handler, in the Android app I can then do this:
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_url"));
setResult(Activity.RESULT_OK, result);
finish();
(source: https://developer.android.com/training/basics/intents/filters.html)
Is this looking right, and how would I implement the same thing on iOS?
END
I deleted my previous question because I couldn't explain the problem clearly, so here goes.
I have a Xamarin Forms app, I want to use a section of this app as a gallery. Currently I have images displayed in a list, and I have an Intent filter set that launches this page when you select the app as the source for an image (such as upload image on Facebook).
My issue is that I don't know how to return the data (the selected image) back to the app / webpage that made the request. In android I understand that you would use StartActivityForResult and OnActivityResult to handle this, but I am using Xamarin Forms (Android, iOS, UWP) and can't really find a solution that could be used cross-platform.
Just a link to documentation that covers this would be great, but if you have an example then even better.
Thanks
EDIT
Here is the code used to launch the app, I am interested in getting data back from the Intent.ActionPick after the user has selected an image from a ListView, which is in a ContentPage in the PCL.
[Activity(Label = "", Icon = "#drawable/icon", Theme = "#style/DefaultTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
[IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = #"*/*")]
[IntentFilter(new[] { Intent.ActionView, Intent.ActionPick, Intent.ActionGetContent }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryOpenable }, DataMimeType = #"*/*")]
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
try
{
base.OnCreate(bundle);
CurrentPlatform.Init();
Xamarin.Forms.Forms.Init(this, bundle);
App _app = new App();
LoadApplication(_app);
if (Intent.Action == Intent.ActionSend)
{
var image = Intent.ClipData.GetItemAt(0);
var imageStream = ContentResolver.OpenInputStream(image.Uri);
var memOfImage = new System.IO.MemoryStream();
imageStream.CopyTo(memOfImage);
_app.UploadManager(memOfImage.ToArray()); //This allows me to upload images to my app
}
else if (Intent.Action == Intent.ActionPick)
{
_app.SelectManager(); //here is where I need help
}
else
{
_app.AuthManager(); //this is the default route
}
}
catch (Exception e)
{
}
}
It seems you cannot use remote URI to provide to calling app. Some posts I checked suggest to store the file locally and provide it's path to calling app. To avoid memory leak with many files stored I suggest to use the same file name then you will have only one file at any moment.
One more note. I tested this solution in facebook. Skype doesn't seem to accept that and, again, the posts I checked saying that Skype doesn't handle Intent properly (not sure what that means).
Now to solution. In main activity for example in OnCreate method add the follow.
ReturnImagePage is the name of my page class where I select an image
Xamarin.Forms.MessagingCenter.Subscribe<ReturnImagePage, string>(this, "imageUri", (sender, requestedUri) => {
Intent share = new Intent();
string uri = "file://" + requestedUri;
share.SetData(Android.Net.Uri.Parse(uri));
// OR
//Android.Net.Uri uri = Android.Net.Uri.Parse(requestedUri);
//Intent share = new Intent(Intent.ActionSend);
//share.PutExtra(Intent.ExtraStream, uri);
//share.SetType("image/*");
//share.AddFlags(ActivityFlags.GrantReadUriPermission);
SetResult(Result.Ok, share);
Finish();
});
Above will listen for the message when the image is selected.
Then in XFroms code when image is selected dowload it, store it, get path and send to Activity using it's path. Below is my test path
MessagingCenter.Send<ReturnImagePage, string>(this, "imageUri", "/storage/emulated/0/Android/data/ButtonRendererDemo.Droid/files/Pictures/temp/IMG_20170207_174559_21.jpg");
You can use static public class to save and access results like:
public static class StaticClass
{
public static int Result;
}

How to check internet connection continuously in Xamarin.Android Native?

My application is completely based on internet and it does not work without it, when the internet is not available or it is slow my application is getting stopped unfortunately.
I tried to implement try, catch but it is not helping me out as it is not throwing any exception, then I thought that I have to check the internet connectivity continuously till the app is running and stop any activity from performing and set a popup to connect to the internet.
I am able to get the popup whenever I call a method which has the following code inside it,
ConnectivityManager connectivityManager = (ConnectivityManager)GetSystemService(ConnectivityService);
NetworkInfo networkInfo = connectivityManager.ActiveNetworkInfo;
if (networkInfo == null)
{
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.SetTitle("Network");
alert.SetMessage("Please turn of your Wifi or Mobile Data From Settings");
alert.SetPositiveButton("OK", (senderAlert, args) => {
Intent intent = new Intent(Android.Provider.Settings.ActionSettings);
StartActivity(intent);
});
alert.SetNegativeButton("Cancel", (senderAlert, args) => {
Toast.MakeText(this, "Cancelled!", ToastLength.Short).Show();
Finish();
});
Dialog dialog = alert.Create();
dialog.Show();
But I am unable to get the connection checked continuously, So Can some one Please help me to complete get this functionality in my application.
You need to use a BroadcastReceiver to monitor network changes.
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "android.net.conn.CONNECTIVITY_CHANGE" })]
[Android.Runtime.Preserve(AllMembers = true)]
public class ConnectivityChangeBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action != ConnectivityManager.ConnectivityAction)
return;
//Check if is connected and raise a custom event or store
//the current in a static global variable
}
}
}
In Android 7.0, you need to remove IntentFilter from the class and register the receiver.
var receiver = new ConnectivityChangeBroadcastReceiver();
Application.Context.RegisterReceiver(receiver, new IntentFilter(ConnectivityManager.ConnectivityAction));
Another option is to use the ConnectivityPlugin https://github.com/jamesmontemagno/ConnectivityPlugin , which is easier to use.
CrossConnectivity.Current.ConnectivityChanged += HandleConnectivityChanged;
void HandleConnectivityChanged (object sender, ConnectivityChangedEventArgs e)
{
// You can check the network status in
//e.IsConnected
}
Note that The ACCESS_NETWORK_STATE and ACCESS_WIFI_STATE permissions are required.

Geofence is not being triggered in the background in windows phone 8.1

I'm trying to implement geofencing in Windows phone 8.1. First I wanted to create a sample Project to understand how it Works, but i couldnt make it works. What I'm trying to achieve is basically, I'll set the coordinates and close the app by pressing back button and it will trigger a toast notification when the phone is in the area of interest.
I've created a blank Windows phone(silverlight) 8.1 Project(geofence_test_01) and added a Windows RT Component Project(BackgroundTask) into the same solution. Added a reference for BackgroundTask in the geofence_test_01 Project.
ID_CAP_LOCATION is enabled in the app manifest.
MainPage.xaml has only one button to start geofencing.
<Button Name="btnStart" Content="Start" Click="btnStart_Click"/>
In btnSave_Click, I call a method which creates the geofence and registers the background task.
private void btnStart_Click(object sender, RoutedEventArgs e)
{
Init_BackgroundGeofence();
registerBackgroundTask();
}
private async Task Init_BackgroundGeofence()
{
//----------------- Crating Geofence ---------------
var geofenceMonitor = GeofenceMonitor.Current;
var geoId = "building9";
var positionBuilding9 = new BasicGeoposition()
{
Latitude = 47.6397,
Longitude = -122.1289
};
var geofence = new Geofence(geoId, new Geocircle(positionBuilding9, 100),
MonitoredGeofenceStates.Entered | MonitoredGeofenceStates.Exited,
false, TimeSpan.FromSeconds(10));
geofenceMonitor.Geofences.Add(geofence);
}
private async Task registerBackgroundTask()
{
//----------------- Register Background Task ---------------
var backgroundAccessStatus =
await BackgroundExecutionManager.RequestAccessAsync();
var geofenceTaskBuilder = new BackgroundTaskBuilder
{
Name = "GeofenceBackgroundTask",
TaskEntryPoint = "BackgroundTask.GeofenceBackgroundTask"
};
var trigger = new LocationTrigger(LocationTriggerType.Geofence);
geofenceTaskBuilder.SetTrigger(trigger);
var geofenceTask = geofenceTaskBuilder.Register();
}
And finally, in BackgroundTask, I've the following code:
namespace BackgroundTask
{
public sealed class GeofenceBackGroundTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
var geofenceMonitor = GeofenceMonitor.Current;
var geoReports = geofenceMonitor.ReadReports();
var geoId = "building9";
foreach (var geofenceStateChangeReport in geoReports)
{
var id = geofenceStateChangeReport.Geofence.Id;
var newState = geofenceStateChangeReport.NewState;
if (id == geoId && newState == GeofenceState.Entered)
{
//------ Call NotifyUser method when Entered -------
notifyUser();
}
}
}
private void notifyUser()
{
var toastTemplate = ToastTemplateType.ToastText02;
var toastXML = ToastNotificationManager.GetTemplateContent(toastTemplate);
var textElements = toastXML.GetElementsByTagName("text");
textElements[0].AppendChild(toastXML.CreateTextNode("You are in!"));
var toast = new ToastNotification(toastXML);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
}
}
I get no error when building and deploying this in the emulator. I set a breakpoint in the backgroundTask but I've not seen that part of code is called yet. It never hits the breakpoint. I test it by using Additional Tools of the emulator, in Location tab, by clicking somewhere in my geofence area on the map, waiting for a while, but it never hits the breakpoint. Hope somebody can tell me what i am missing here...
I've checked these following links to build this application:
http://www.jayway.com/2014/04/22/windows-phone-8-1-for-developers-geolocation-and-geofencing/
Geofence in the Background Windows Phone 8.1 (WinRT)
Toast notification & Geofence Windows Phone 8.1
http://java.dzone.com/articles/geofencing-windows-phone-81
Thanks
You can download the project here:
https://drive.google.com/file/d/0B8Q_biJCWl4-QndYczR0cjNhNlE/view?usp=sharing
---- Some clues
Thanks to Romasz, I've checked the Lifecycle events and i see "no background tasks" even after registerBackgroundTask() is executed.... Apparently there is something wrong/missing in registerBackgroundTask() method.
I've tried to build my sample (it was easier for me to build a new one) basing on your code and it seems to be working. You can take a look at it at my GitHub.
There are couple of things that may have gone wrong in your case:
remember to add capabilities in WMAppManifest file (IS_CAP_LOCATION) and Package.appxmanifest (Location)
check the names (of namespaces, classes and so on) in BackgroundTask
check if your BackgroundTask project is Windows Runtime Componenet and is added to your main project as a reference
I know you have done some of this things already, but take a look at my sample, try to run it and maybe try to build your own from the very beginning.
Did you add your background task in the Package.appxmanifest under Declarations with the correct supported task types (Namely Location)?

How to I get access NavigationService in a WIndows Phone app without going through a PhoneApplicationPage?

How to I get access NavigationService in a Windows Phone app without going through a PhoneApplicationPage? My goal is to pass it to the application's primary view-model on startup, a technique that worked quite well for me in WPF and Silverlight.
You can get it from the app's PhoneApplicationFrame. It will be accessible from anywhere in the app since every Windows Phone app has a Frame.
((PhoneApplicationFrame)Application.Current.RootVisual).Navigate(...);
Another place to get it is from the RootFrame field in the default implementation of Application:
#region Phone application initialization
// Avoid double-initialization
private bool phoneApplicationInitialized = false;
// Do not add any additional code to this method
private void InitializePhoneApplication()
{
if (phoneApplicationInitialized)
return;
// Create the frame but don't set it as RootVisual yet; this allows the splash
// screen to remain active until the application is ready to render.
RootFrame = new PhoneApplicationFrame();
RootFrame.Navigated += CompleteInitializePhoneApplication;
// Handle navigation failures
RootFrame.NavigationFailed += RootFrame_NavigationFailed;
// Ensure we don't initialize again
phoneApplicationInitialized = true;
}
// Do not add any additional code to this method
private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
{
// Set the root visual to allow the application to render
if (RootVisual != RootFrame)
RootVisual = RootFrame;
// Remove this handler since it is no longer needed
RootFrame.Navigated -= CompleteInitializePhoneApplication;
}
#endregion

Resources