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;
}
Related
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.
System-Environment:
Windows 10 Pro - Version: 1909 - OS System Build: 18363.752
Microsoft Outlook 2019 MSO - Version 1808 - 32-Bit
Microsoft Exchange 2016 15.1 Build (Build 1979.3)
-- Microsoft Exchange is installed on Microsoft Server 2016
Outlook Redemption COM-Library - Version 5.22.0.5498
Issue Summary:
The application sends emails via Outlook using the Outlook-Redemption COM-Library. The class "RedemptionHandler" is our Singleton-Class which interacts with the Outlook-Redemption COM-Library. During the construction of the RedemptionHandler we create a RDOSession with a static class named RedemptionLoader and call Logon() on the RDOSession. The RDOSession is used afterwards in Initialize() to retrieve the Folders for Drafts and mails which are sent.
public static class RedemptionLoader
{
public static RDOSession new_RDOSession()
{
return (RDOSession)NewRedemptionObject(new Guid("29AB7A12-B531-450E-8F7A-EA94C2F3C05F"));
}
}
public class RedemptionHandler
{
private static RedemptionHandler instance = null;
private static readonly object padlock = new object();
private RDOSession _rdoSession;
private RDOFolder _rdoSentFolder;
private RDOFolder _rdoDraftsFolder;
private RDOItems _sentItems = null;
public EventHandler<MailGesendetEventArgs> MailSuccessfullySent;
private RedemptionHandler()
{
_rdoSession = RedemptionLoader.new_RDOSession();
_rdoSession.Logon(null, null, false, null, null, null);
Initialize();
}
public static RedemptionHandler Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new RedemptionHandler();
}
return instance;
}
}
}
private void Initialize()
{
try
{
if (isInitialized) return;
_rdoSentFolder = _rdoSession.GetDefaultFolder(Redemption.rdoDefaultFolders.olFolderSentMail);
_sentItems = _rdoSentFolder.Items;
_sentItems.ItemAdd += MailSent;
_rdoDraftsFolder = _rdoSession.GetDefaultFolder(Redemption.rdoDefaultFolders.olFolderDrafts);
isInitialized = true;
}
catch
{
//TODO
isInitialized = false;
}
}
}
At this point, we have a working instance from our RedemptionHandler. The COM-Object RDOSession is created and referenced within just as the RDOFolder for Drafts and Sent. We have also registrered an event-listener for the Sent-Folder to recognize new Mails in this folder.
In the next steps we want to send an email and recognize this email if its stored in the sent-folder. We use the RDOMail.Fields - Property to store custom data within the RDOMail-Object.
public RDOMail CreateMail(string recipient, string subject, string body, Guid gdSender, string storagePath)
{
RDOMail newMail = _rdoDraftsFolder.Items.Add(Redemption.rdoItemType.olMailItem);
newMail.Recipients.Add(recipient);
newMail.Recipients.ResolveAll();
newMail.Subject = subject;
newMail.HTMLBody = body;
newMail.BodyFormat = (int)rdoBodyFormat.olFormatHTML;
// Here we want to store an identifier in the RDOMail.Fields
int id = newMail.GetIDsFromNames(PropertyGuid, PropertyGdItemId);
newMail.Fields[id] = Guid.NewGuid().ToString();
return newMail;
}
After the mail creation we want to display the mail to the user because we dont want to send data without letting the user know about it.
public void DisplayMail(RDOMail mail, bool modal = false)
{
mail.Display(modal, null);
}
The Outlook window now comes to front and the user checks the mail and clicks on send.
The Mail is now stored in the Sent-Folder.
The MailSent Event gets invoked by the RDOFolder.Items.Add Listener.
private void MailSent(RDOMail mail)
{
var test = mail.Fields[SenderId];
Console.WriteLine(test);
// test value is correct!
}
Difference between Exchange in Online-Mode and Cache-Mode:
If we use the Exchange with Cache-Mode, everything works fine. Everytime we send an email, the MailSent is triggered and we can read data from the RDOMail.Fields-Property. If we switch to Exchange without Cache, the MailSent Event is triggered only once, when the first mail is sent. All emails afterwars are sent but dont trigger the MailSent-Event. If we delete this line of code, everything works also fine without Cache-Mode.
var test = mail.Fields[SenderId];
This is because we think that reading data from the RDOMail.Fields - Property does something special if the cache-mode from exchange is deactivated.
We need to store custom data within the mails to check if new mails in the sent-folder are created by our application or not.
We highly appreciate help and hints.
I tried to fix this issue without success. I've set-up a new Project without any other code:
public partial class RedemptionTest : Form
{
static RDOSession _rdoSession;
static RDOFolder _rdoSentFolder;
static RDOFolder _rdoDraftsFolder;
static RDOItems _draftItems;
static RDOItems _sentItems;
public RedemptionTest()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_rdoSession = RedemptionLoader.new_RDOSession();
_rdoSession.Logon();
_rdoSentFolder = _rdoSession.GetDefaultFolder(rdoDefaultFolders.olFolderSentMail);
_rdoDraftsFolder = _rdoSession.GetDefaultFolder(rdoDefaultFolders.olFolderDrafts);
_sentItems = _rdoSentFolder.Items;
_draftItems = _rdoDraftsFolder.Items;
_draftItems.ItemAdd += DraftAdd;
_sentItems.ItemAdd += MailSent;
}
private void DraftAdd(RDOMail Item)
{
Console.WriteLine(Item.Subject);
}
private void MailSent(RDOMail Item)
{
Console.WriteLine(Item.Subject);
}
}
The Drafts-Folder Event is fired all the time, the MailSent Event is only fired the first time. I have stored all RDO-Objects in static variables to avoid them from being garbage collected.
The object raising the events (RDOItems) must be alive be able to fire the events. Your code is using multiple dot notation, which means the compiler creates an implicit variable to hold the RDOItems collection. As soon as that variable is released by the Garbage Collector, no events will be fired.
The line
_rdoSentFolder.Items.ItemAdd += MailSent;
must be changed to
RDOItems _sentItems; //global/class variable
..
_sentItems = _rdoSentFolder.Items;
_sentItems .ItemAdd += MailSent;
Have the same issue in Outlook VSTO add-in using Redemption. Happens for both Sent and Inbox folder. The same code works correctly in cached mode but fires events only once in Online mode.
Native Outlook object model Items.ItemAdd works correctly in Online mode for the same folder.
Currently, we were able to do a workaround for this by unsubscribing and resubscribing to event right in the event handler. Like this:
private void SentItems_ItemAdd(RDOMail rdoMail)
{
_sentItems.ItemAdd -= SentItems_ItemAdd;
_sentItems.ItemAdd += SentItems_ItemAdd;
Log.Debug("SentItems.ItemAdd");
SentMailItemAdd?.Invoke(rdoMail);
}
So i'm using Azure Notification Hub, and in that i followed their tutorial where they had mentioned to use FCM for Android , configure it and use their API key, and creating a certificate for iOS, which is working flawless
But the problem is i'm working on Xamarin forms, and i'd like to know if i could do the registration manually through API, and i've already written a method to do that in my API Service
public async Task<string> RegisterDevice([FromBody] string handle = null)
{
string newRegistrationId = null;
//newRegistrationId = await hub.CreateRegistrationIdAsync();
//// make sure there are no existing registrations for this push handle (used for iOS and Android)
//if (handle != null)
//{
// var registrations = await hub.GetRegistrationsByChannelAsync(handle, 100);
// foreach (var registration in registrations)
// {
// if (newRegistrationId == null)
// {
// newRegistrationId = registration.RegistrationId;
// }
// else
// {
// await hub.DeleteRegistrationAsync(registration);
// }
// }
//}
newRegistrationId = await hub.CreateRegistrationIdAsync();
return newRegistrationId;
}
But i'm not able to understand how the device would be linked to this registration ID and/or what is a pns handle, i know the abbreviation but i dont know how to use it in this case or if at all is it necessary?
Any help would be deeply appreciated
While registering Azure Notification Hub, If you want to ask for Push permissions after login, you have to call RegisterForRemoteNotifications(); (iOS) & CreateNotificationChannel(); (Android) after Login.
What you're asking would require a few steps-
You would have to created a DependencyService like this, which would require creating an Interface like IPushRegistrationService with a RegisterForPush() function that would basically be called after login:
var pushService = DependencyService.Get<IPushRegistrationService>();
pushService.RegisterForPush();
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);
How can I create a Share button (that share a defined mesage to another player contact) as the below image on Windows Phone 8, 8.1 and 10 (Mobile):
To create this script to share on Android Device I use the following code:
public class ShareScript : MonoBehaviour {
string subject = "Subject";
string body = "Body";
public void OnAndroidTextSharingClick()
{
StartCoroutine(ShareAndroidText());
}
IEnumerator ShareAndroidText()
{
yield return new WaitForEndOfFrame();
//execute the below lines if being run on a Android device
#if UNITY_ANDROID
//Reference of AndroidJavaClass class for intent
AndroidJavaClass intentClass = new AndroidJavaClass ("android.content.Intent");
//Reference of AndroidJavaObject class for intent
AndroidJavaObject intentObject = new AndroidJavaObject ("android.content.Intent");
//call setAction method of the Intent object created
intentObject.Call<AndroidJavaObject>("setAction", intentClass.GetStatic<string>("ACTION_SEND"));
//set the type of sharing that is happening
intentObject.Call<AndroidJavaObject>("setType", "text/plain");
//add data to be passed to the other activity i.e., the data to be sent
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_SUBJECT"), subject);
//intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TITLE"), "Text Sharing ");
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), body);
//get the current activity
AndroidJavaClass unity = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = unity.GetStatic<AndroidJavaObject>("currentActivity");
//start the activity by sending the intent data
AndroidJavaObject jChooser = intentClass.CallStatic<AndroidJavaObject>("createChooser", intentObject, "Share Via");
currentActivity.Call("startActivity", jChooser);
#endif
}
}
Call DataTransferManager.ShowShareUI to show the sharing pane.
Handle the DataTransferManager.DataRequested event to provide the data when the user choses to share.
private void DataRequested(DataTransferManager sender, DataRequestedEventArgs e)
{
DataRequest request = e.Request;
request.Data.Properties.Title = "Share Text Example";
request.Data.Properties.Description = "An example of how to share text.";
request.Data.SetText("Hello World!");
}
See the Share data docs on MSDN for more info.
In Unity you can call these in an #if NETFX_CORE block so it runs only when using the Windows Runtime and not Mono. See Windows Store Apps: WinRT API in C# scripts. If you target Windows 10 then there are plug-ins at https://github.com/microsoft/unityplugins which include sharing. For earlier targets there are commercial plugins.