I am currently working on Windows 8.1 Push Notification part. I have read different links and found that first we need to register the app and get all the information like SID and Client Secret and send to our server team so they can send push notification.
Then after this, I implemented the following code at my side to get channelUri and Expiration date of that Uri from WNS.
PushNotificationChannel channel = null;
try
{
channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
if (channel != null)
{
var notificationUri = channel.Uri;
var expiration_time = channel.ExpirationTime;
}
channel.PushNotificationReceived += channel_PushNotificationReceived;
}
catch (Exception ex)
{
if (ex != null)
{
System.Diagnostics.Debug.WriteLine(ex.HResult);
}
}
I have received all the values perfectly and my server team added a logic to send me push notification. Now, the problem which I am facing is that I am not aware how to display the received push notification sent by server to that user. Also, can we display the notification is the app is not running or is in background?
Background Tasks solved my problem.
First you need to create a WindowsRuntimeComponent Project and add the code below
public sealed class PushNotification:IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
RawNotification notification = (RawNotification)taskInstance.TriggerDetails as RawNotification;
if (notification != null)
{
ToastTemplateType toastTemplate = ToastTemplateType.ToastImageAndText01;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
var textElemets = toastXml.GetElementsByTagName("text");
textElemets[0].AppendChild(toastXml.CreateTextNode(notification.Content));
var imageElement = toastXml.GetElementsByTagName("image");
imageElement[0].Attributes[1].NodeValue = "ms-appx:///Assets/50.png";
ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml));
}
}
}
Then register the background task in any of the page( i added in Home Page) using below code
private async void RegisterBackgroundTask()
{
await BackgroundExecutionManager.RequestAccessAsync();
try
{
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
try
{
task.Value.Unregister(false);
}
catch
{
//
}
}
BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
builder.Name = "Push Notifcation Task";
builder.TaskEntryPoint = typeof(PushNotification).FullName;
builder.SetTrigger(new PushNotificationTrigger());
builder.Register();
}
catch(Exception e)
{
if(e != null)
{
System.Diagnostics.Debug.WriteLine(e.HResult);
System.Diagnostics.Debug.WriteLine(e.InnerException);
}
}
}
Please don't forget to add this background task in Declarations section in Package.appmanifest file and name of Entry Point should match with builder.TaskEntryPoint = typeof(PushNotification).FullName; else you will get exception.
Hope it helps someone.
Related
The following works ok:
using Plugin.FilePicker;
using Plugin.FilePicker.Abstractions;
using Xamarin.CommunityToolkit.Core;`
...
private void btnPlaySource_Clicked(object sender, EventArgs e)
{
FileData fileData = await CrossFilePicker.Current.PickFile();
if (fileData == null)
return; // user canceled file picking
mediaElement.Source = MediaSource.FromFile(fileData.FilePath);
mediaElement.Play();
}
But these lines throw an exception with a delay of ~7 secs (it's not immediately thrown):
private void btnPlayURL_Clicked(object sender, EventArgs e)
{
//http://docs.google.com/uc?export=open&id=XXXXXXXXXXXXXXXXXX
var fileURL = GetGDriveFileURL();
mediaElement.Source = MediaSource.FromUri(fileURL);
mediaElement.Play();
}
Java.Lang.RuntimeException: 'setDataSource failed: status = 0x80000000'
What could be the reason of the exception? The URL is 100% working, I tested it on a WPF application's MediaElement and it played fine. I also build the application for Android with Android API level 29 SDK.
<Grid><xct:MediaElement x:Name="mediaElement" Grid.Row="0" AutoPlay="False" ShowsPlaybackControls="True"/>
Some of the problems were solved using Xamarin.Essentials.FilePicker. It allows picking audio from Google Drive if it's connected to the Android device. Although, the problem with URL still remains.
//var fileResult = await App.PickAndShow(Xamarin.Essentials.PickOptions.Default);
//if (fileResult == null) return false;
public static async Task<string> PickAndShow(Xamarin.Essentials.PickOptions options)
{
try {
Xamarin.Essentials.FileResult result =
await Xamarin.Essentials.FilePicker.PickAsync(options);
if (result != null) {
// For certain types of files, like ".mp3"
if (result.FileName.EndsWith("mp3", StringComparison.OrdinalIgnoreCase) ||
result.FileName.EndsWith("wav", StringComparison.OrdinalIgnoreCase))
{
// for debug purposes
bool exists = File.Exists(result.FullPath);
}
}
return result.FullPath;
} catch (Exception ex) {
// The user canceled or something went wrong
}
return null;
}
I'm developing another sample where Messaging Center send status messages not coupled from device code to my view models.
At this point I used:
A alert message;
Label in my view;
A method by dependency injection from native code(interfaced and created before).
To notice the events before try in View models... etc
For it I used a static view instance in my share application constructor (App.xaml) where in view constructor I Subscript the status.
App (shared)
public partial class App : Application
{
public static ConnectViewModel CVM { get; set; }// Connection View Model
#region MasterDetailPage
public static MasterDetailPage MDP;
public static NavigationPage NAV = null;
public static MainView _mainpage;
#endregion
public App ()
{
InitializeComponent();
InitializeApplication();
NAV = new NavigationPage(new StarterView()) { BarBackgroundColor = Color.FromHex("701424"), BarTextColor = Color.White }; ;
MDP = new MasterDetailPage();
MDP.BackgroundColor = Xamarin.Forms.Color.FromHex("701424");
_mainpage = new MainView();
MDP.Master = _mainpage;
MDP.Detail = NAV;
MainPage = MDP;
MainPage.Title = "H2X";
}
private void InitializeApplication()
{
if (CVM == null)
{
CVM = new ConnectViewModel();
}
}
(View shared)
public MainView ()
{
InitializeComponent ();
string a="Test";
#region MessegeCenter
MessagingCenter.Subscribe<string,string>("APP", "Message_Received", async (sender,arg) =>
{
string b = a;
a = $"{arg}";
try
{
* await DisplayAlert(App.BM_Status, "Ok", "OK");*
}catch(Exception e)
{
string a = e.Message;
}
* generic_label_of_my_view = generic_label_of_my_view + "+";//It's not async one*
*string test = App.CVM.All_conn.Msg_Reciever();//Injection - It's not async one*
});
#endregion
}
Into the specific platform code (Device - UWP):
I create a timer that sends messages after some time instanced in mainpage constructor.
A HID device that notice me when some msg comes from USB.
The dispatcherTimer
void dispatcherTimer_Tick(object sender, object e)
{
DateTimeOffset time = DateTimeOffset.Now;
TimeSpan span = time - lastTime;
lastTime = time;
//Time since last tick should be very very close to Interval
TimerLog.Text += timesTicked + "\t time since last tick: " + span.ToString() + "\n";
timesTicked++;
if (timesTicked > timesToTick)
{
MessagingCenter.Send<string,string>("APP","Message_Received","MR");
}
}
The HIDInit and HID InputReport event
public async void HID_Init()
{
var selector = HidDevice.GetDeviceSelector(a_Id, b_Id, c_ID, d_ID);
var devices = await DeviceInformation.FindAllAsync(selector);
if (devices.Any())
{
// At this point the device is available to communicate with
// So we can send/receive HID reports from it generically
console_text = "HID devices found: " + devices.Count;
device = await HidDevice.FromIdAsync(devices.ElementAt(0).Id, FileAccessMode.ReadWrite);
if (device != null)
{
// At this point the device is available to communicate with
// create my input caller/event
device.InputReportReceived += inputReportReceived;//invoke caller
deviceWatcher = DeviceInformation.CreateWatcher(selector);
deviceWatcher.Removed += deviceRemovedEventHandler;//checa se nada foi removido
deviceWatcher.Start();
}
else
{
// There were no HID devices that met the selector criteria
throw new Exception("MUTT HID device not found");
}
}
else
{
// There were no HID devices that met the selector criteria
console_text = "HID device not found";
}
}
private void inputReportReceived(HidDevice sender, HidInputReportReceivedEventArgs args)
{
var bbytes = new byte[10];
wait_streaming = true;
DataReader dataReader = DataReader.FromBuffer(args.Report.Data);
dataReader.ReadBytes(bbytes);
console_text += System.Text.Encoding.ASCII.GetString(bbytes, 2, bbytes[1]);
is_read = false;
wait_streaming = false;
MessagingCenter.Send<string,string>("App","Message_Received","MR");
}
When I run any case with Dispatchertimer "works".
When I run by the Hidinputreport event with the alertmessage creates a system.exception in alertmessege line.
This is the "System.Exception"
if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
UnhandledException += (sender, e) =>
{
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
};
endif
When I run by the Hidinputreport event with the Label a marshalled interface crash with other thread in my call from messegingCenter in native code.
System.Exception: 'The application call a marshalled interface for another thread.
(Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))'
When I run the injection, works but I'm afraid that this Thread troubles make some semantical bug in my project cause I need to call INofifyPropertyChanged in shared code to print in my view the message but ...
Can I call it into the sender into Messeging Center Subscripte ?
How can I correct the other troubles with Threads ? Manual Reset Events ? EventWaitHandle ? (Inheritance:Object->MarshalByRefObject->WaitHandle->EventWaitHandle) ... so invasive way :/
I'm sorry if I ask some stupid question or show stupit code here ... but I don't know how to organize it WELL
Thank you in advance
Guilherme
I have a background task that is supposed to open a toast message, à la: ToastNotificationManager.CreateToastNotifier().Show(toast);. My code executes fine, no errors are thrown, nothing hangs -- but also, no toast message appears.
I checked the Event Viewer logs, and they say this:
An instance of the background task with entry point
BG.ToastBackgroundTask running for user [me] in session [sesh]
returned with error code 0x0.
I have looked all over to see what this error code might mean but found nothing.
Here's my code:
public sealed class ToastBackgroundTask : IBackgroundTask
{
private BackgroundTaskDeferral _deferral;
public async void Run(IBackgroundTaskInstance taskInstance)
{
var cancelToken = new System.Threading.CancellationTokenSource();
taskInstance.Canceled += (s, e) =>
{
cancelToken.Cancel();
cancelToken.Dispose();
};
taskInstance.Task.Completed += Task_Completed;
_deferral = taskInstance.GetDeferral();
try
{
await SendNotificationAsync();
}
finally { _deferral.Complete(); }
}
public static async void Register()
{
var isRegistered = BackgroundTaskRegistration.AllTasks.Values.Any(x => x.Name == nameof(ToastBackgroundTask));
if (isRegistered) return;
var accessStatus = await BackgroundExecutionManager.RequestAccessAsync();
if (accessStatus == BackgroundAccessStatus.DeniedByUser || accessStatus == BackgroundAccessStatus.DeniedBySystemPolicy) return;
var builder = new BackgroundTaskBuilder
{
Name = nameof(ToastBackgroundTask),
TaskEntryPoint = $"{nameof(MyNameSpace)}.{nameof(BG)}.{nameof(ToastBackgroundTask)}"
};
builder.SetTrigger(new TimeTrigger(120, false));
var task = builder.Register();
}
private static void Task_Completed(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
{
try
{
args.CheckResult();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
private Task SendNotificationAsync()
{
var service = new ToastService();
service.CreateToast(new ToastViewModel { Title = "Title", Text = "Text", ImagePath = "", Id = 3 });
return Task.CompletedTask;
}
}
If I run CheckResult() on the completed task, no errors are thrown. Argh! Does anyone know (a) what this Event Viewer log error means, or (b) why my toast isn't showing up?
Here's my Toast code too in case it helps:
public class ToastService
{
public void CreateToast(ToastViewModel model)
{
var visual = new ToastVisual()
{
BindingGeneric = new ToastBindingGeneric()
{
Children =
{
new AdaptiveText() { Text = model.Title },
new AdaptiveText() { Text = model.Text }
},
Attribution = new ToastGenericAttributionText() { Text = "Via Me" }
}
};
var tContent = new ToastContent()
{
Visual = visual,
ActivationType = ToastActivationType.Background,
Scenario = ToastScenario.Reminder
};
var toast = new ToastNotification(tContent.GetXml())
{
ExpirationTime = DateTime.Now.AddDays(model.Expiration)
};
toast.Failed += (o, args) => {
var message = args.ErrorCode;
};
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
}
Does anyone know (a) what this Event Viewer log error means, or (b) why my toast isn't showing up?
The above event log showed on my side is information level, not error level. The reason for the toast isn't showing up should be that you setting the ExpirationTime property for the ToastNotification. This property is for:
Gets or sets the time after which a toast notification should not be displayed.
So that if the model.Expiration equals to 0, the toast will not show from now. Ensure the expiration time later than now should work.
var toast = new ToastNotification(tContentxml)
{
ExpirationTime = DateTime.Now.AddDays(1)
};
Otherwise your code snippet can work will on my side. If you still have issues, you can provide a minimal reproduced project to let us have a testing.
I've done a lot of work over the past week, working with creating background task for a windows universal project. I've having a hard, and starting believe it is not possible triggering a background task to run when the device screen is locked. I'm using SystemTriggerType.Useraway to trigger the background task. I'll post what i've got so far. Any help with this would be awesome!
Here's how I am registering the background task
public static void RegisterTask()
{
try
{
var taskRegistered = false;
var builder = new BackgroundTaskBuilder();
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == "ResponderBackgroundTask")
{
Debug.WriteLine(task.Value.Name + " Task Already Registered!!");
taskRegistered = true;
break;
}
}
if (!taskRegistered)
{
builder.Name = "ResponderBackgroundTask";
builder.TaskEntryPoint = "BackgroundGps.BackgroundTask";
builder.AddCondition(new SystemCondition(SystemConditionType.UserNotPresent));
builder.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable));
builder.SetTrigger(new SystemTrigger(SystemTriggerType.UserAway, false));
builder.CancelOnConditionLoss = true;
var register = builder.Register();
register.Completed += new BackgroundTaskCompletedEventHandler(OnComplete);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
throw;
}
}
Here is the backgroundtask:
async public void Run(IBackgroundTaskInstance taskInstance)
{
taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
Debug.WriteLine("Inside Run.......");
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
await Geolocate();
deferral.Complete();
}
async static Task<HttpResponseMessage> Geolocate()
{
Debug.WriteLine("Inside Async Geolocate");
HttpResponseMessage response = new HttpResponseMessage();
Geolocator geolocator = new Geolocator();
geolocator.DesiredAccuracy = (PositionAccuracy) 20;
geolocator.DesiredAccuracyInMeters = 30;
var networkStatus = NetworkInformation.GetInternetConnectionProfile();
bool status = true;
while (status)
{
networkStatus = NetworkInformation.GetInternetConnectionProfile();
Geoposition position = await geolocator.GetGeopositionAsync().AsTask();
var latitude = position.Coordinate.Point.Position.Latitude;
var longitude = position.Coordinate.Point.Position.Longitude;
HttpClient client = new HttpClient();
response = await client.GetAsync("http://www.mylocation.com/location?=latitude&longitude");
Debug.WriteLine(response);
if (networkStatus == null)
{
status = false;
}
if (cancelRequest == true)
{
return response;
}
await Task.Delay(15000);
}
return response;
}
I had some issues with background task in UWP project when I've used it for push notifications.
The main issue with UWP BackgroundTasks is that they suppose to be very light and consume not much of CPU time, otherwise the OS shuts it down.
My problem was, that I've tried to access the local database by using very heavy service, which took CPU time and were shutdown by the OS. My logs were cut in the middle of a line, cause my logger won't be fast enough to write the message.
Try to put some logs in your BackgroundTask inorder to see if he raised by the trigger, and look for a heavy operation that can cause it to be canceled.
Web requests can be also the problem...
i want to know how to insert MobileServiceCollection from Windows Azure to my ObservableCollection from JSON web service
private ObservableCollection<AddressDetail> _hereRestAddressDetail = null;
public ObservableCollection<AddressDetail> hereRestAddressDetail
{
get { return _hereRestAddressDetail; }
set { this.SetProperty(ref this._hereRestAddressDetail, value); }
}
private async void UpdateTransportDetail()
{
try
{
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
if (e.Error == null)
{
RootObjectDetail result = JsonConvert.DeserializeObject<RootObjectDetail>(e.Result);
hereRestAddressDetail.Clear();
hereRestAddressDetail.Insert(0,result);
}
else
{
isFailed = Visibility.Visible;
isFailedMessage = "Can't get data from web server, please refresh and make sure your internet data connected";
}
};
client.DownloadStringAsync(new Uri(hrefText + transportDetailURL));
hereRestAddressDetail = await addressTable.ToCollectionAsync();
}
catch (Exception)
{
isFailed = Visibility.Visible;
isFailedMessage = "Something wrong happen, please refresh";
}
}
and what i try to do is to add my azure data into the next entry of hereRestAddressDetail (since the first is from json web service) with this
hereRestAddressDetail = await addressTable.ToCollectionAsync();
but it just replace the data from json not adding it, how can i make it appear with my json data also?
Not sure if the question is still actual, but you can replace the while collection
hereRestAddressDetail = new ObservableCollection<AddressDetail>(await addressTable.ToCollectionAsync());
Or (i'd recommend this way) grab OptimizedObservableCollection ( for example, here: http://www.pedrolamas.com/2013/05/08/cimbalino-windows-phone-toolkit-updated-to-v2-3-0/ ) and use it like
hereRestAddressDetail.ReplaceWith(await addressTable.ToCollectionAsync()); // replace
or
hereRestAddressDetail.AddRange(await addressTable.ToCollectionAsync()); // add