Webview is getting reloaded when app goes into background Xamarin - webview

Everytime when app goes background and comes foreground webview is getting reloaded. I just want to save the state in onpause and reload it when I resume the app.Could it be possible?
I am unable to do that. Any help would be greatly appreciated.
protected override void OnCreate(Bundle bundle)
{
if (bundle == null) { //everytime when I load, bundle is null and url is reloaded
mapWebView.LoadUrl("url");
} else {
mapWebView.RestoreState(bundle);
}
}
protected override void OnResume() {
base.OnResume();
if (mapWebView != null)
mapWebView.OnResume();
}
protected override void OnPause()
{
base.OnPause();
if (mapWebView != null)
{
mapWebView.OnPause();
mapWebView.SaveEnabled = true;
mapWebView.SaveState(bundle) //how to get bundle object here to save state
}
}

mapWebView.SaveState(bundle) //how to get bundle object here to save state
To get Bundle you need to override method
public override void OnSaveInstanceState (Bundle outState, PersistableBundle outPersistentState) {
base.OnSaveInstanceState (outState, outPersistentState);
}
Everytime when app goes background and comes foreground webview is getting reloaded. I just want to save the state in onpause and reload it when I resume the app.
From your question it's hard to understand when you want to reload webview. Because onPause and OnResume will be called every time your app goes background/foreground.

Related

How to use SendBird logging on application level

My Xamarin.iOS project keeps crashing with no explanation, and I reckon it's because of something I'm doing with SendBird, since I'm not seeing any explanation in the application output when my app crashes. How can I see logs of SendBird? This is what I am trying:
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// other code...
SendBird.SendBirdClient.Log = SendBirdLog;
return true;
}
private void SendBirdLog(string message)
{
// this never gets called
Console.WriteLine(message);
}
But my SendBirdLog function never gets called. I am using the latest SendBird.dll from here:
https://github.com/sendbird/Sendbird-SDK-dotNET#before-getting-started

How to stop video playing in WebView

I work on a Xamarin.Forms app (UWP!). It has a Master-Details architecture. The Master page has a ListView, and each item in it opens a corresponding Detail page. The first Detail page has only a WebView that plays a YouTube video upon loading. The second Detail view has just a placeholder label for now.
Where I switch from first Detail page to the second, the sound of the video from the first Detail page is still heard. And when I switch back to the first Detail page, the video loads again, and now I hear two voices. How can I stop the video upon switching to the second Detail page and resume when going back? If this is not possible, how can I just stop the video upon leaving its Detail page?
I guess I could do something in an overridden OnDisappearing() method of the detail page:
protected override void OnDisappearing()
{
MyWebView.NavigateToString(""); // This does not work, as NavigateToString() is not part of WebView.
base.OnDisappearing();
}
What can I use to stop playing video in WebView?
Could you please tell what I can use to stop playing video in WebView?
For your requirement, you could approach with injecting Eval java script.
private void Button_Clicked(object sender, EventArgs e)
{
string pausefunctionString = #"
var videos = document.querySelectorAll('video');
[].forEach.call(videos, function(video) { video.pause(); });
";
MyWebView.Eval(pausefunctionString);
}
Update
I have re-checked your issue, when you navigate to another page, the WebView has not be released correctly. If you want to stop the WebView video play, you could make it navigate to blank page via custom WebViewRenderer.
[assembly: ExportRenderer(typeof(WebView), typeof(CustomWebViewRender))]
namespace App4.UWP
{
class CustomWebViewRender : WebViewRenderer
{
private Windows.UI.Xaml.Controls.WebView _WebView;
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var source = Element.Source as UrlWebViewSource;
_WebView = new Windows.UI.Xaml.Controls.WebView();
SetNativeControl(_WebView);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == WebView.SourceProperty.PropertyName)
{
var source = Element.Source as UrlWebViewSource;
if (source.Url == string.Empty)
{
_WebView.NavigateToString(string.Empty);
}
}
}
}
}
Usage
protected override void OnAppearing()
{
base.OnAppearing();
MyWebView.Source = "https://www.youtube.com";
}
protected override void OnDisappearing()
{
MyWebView.Source = string.Empty;
base.OnDisappearing();
}
Xaml
<WebView HeightRequest="500" WidthRequest="500" x:Name="MyWebView"/>

How to get notified when Xamarin Native Android app goes to sleep or is terminated?

How to get notified when Xamarin Native Android app goes to sleep or is terminated?
When searching, I only found an answer for Xamarin.Forms where the Application object allows to override OnSleep.
The background of this question is that I want to save settings when the app either goes to background or is terminated.
Just like the OnSleep method of Xamarin Forms the OnPause method is called in Android Native when the app goes into the background.
You can override OnPause in both an Activity and a Fragment something like this:
protected override void OnPause()
{
base.OnPause();
// Add your code here
}
Update
You can do the same on application level by adding the Android Application class :
Add a new C# class file in your project called MainApplication.cs.
Then add the Application.IActivityLifecycleCallbacks interface where you can find the activity paused method with the activity context in which it was paused so you can add it and do the needful.
#if DEBUG
[Application(Debuggable = true)]
#else
[Application(Debuggable = false)]
#endif
public class MainApplication : Application , Application.IActivityLifecycleCallbacks
{
public MainApplication(IntPtr handle, JniHandleOwnership transer)
: base(handle, transer)
{
}
public void OnActivityPaused(Android.App.Activity activity)
{
base.OnCreate();
// Add some code
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
}
}

Handle local notification tap Xamarin Forms iOS

I have created an application on Xamarin Forms in which I am scheduling local notifications in PCL through a Plugin named Plugin.Notifications. But I wanted to know whether the user enters into the app through notification or not.
I tried to check whether the UIApplication.LaunchOptionsLocalNotificationKey is present in the launch 'options' dictionary or not, but the launch options dictionary is always null.
Then I tried to handle it through the ReceivedLocalNotification delegate method, and I was able to get the tap event, it works fine when the app is in foreground or in the background, but when the app gets killed and opens through tapping on the notification, its getting crashed.
I am unable to find the issue for the crash.
here is what I am doing in the ReceivedLocalNotification method.
I am setting a bool value through a DependencyService.
public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification)
{
NSUserDefaults.StandardUserDefaults.Init();
DependencyService.Get<INotificationTap>().SetNoitificationTap(true);
}
The handling of the Dependency Service
[assembly: Xamarin.Forms.Dependency(typeof(NotificationTapIOS))]
namespace abc.iOS
{
public class NotificationTapIOS:NSObject,INotificationTap
{
public bool GetNotificationTap()
{
return NSUserDefaults.StandardUserDefaults.BoolForKey("notificationTapKey");
}
public void SetNoitificationTap(bool isNotificationTapped)
{
NSUserDefaults.StandardUserDefaults.SetBool(isNotificationTapped,"notificationTapKey");
NSUserDefaults.StandardUserDefaults.Synchronize();
}
}
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
if (options != null)
{
// check for a local notification
if (options.ContainsKey(UIApplication.LaunchOptionsLocalNotificationKey))
{
var localNotification = options[UIApplication.LaunchOptionsLocalNotificationKey] as UILocalNotification;
if (localNotification != null)
{
LoadApplication(new App());
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;// reset our badge
}
}
}
else
{
LoadApplication(new App());
}
}
I found a workaround for this issue, I don't know whether this is a correct approach, but it worked for me.
In Xamarin.iOS , when the app launched , the base class methods are called first(i.e applicationDidFinishLaunching) and then the Xamarin part(i.e FinishedLaunching) is called.
So I changed the FinishedLaunching parameters names , similar to the base class parameters (i.e 'app' to 'uiApplication' and 'options' to 'launchOptions' ) and I got the key in the launchOptions Dictionary.
public override bool FinishedLaunching(UIApplication uiApplication, NSDictionary launchOptions)
{
global::Xamarin.Forms.Forms.Init();
isNotificationTapped = false;
if (launchOptions != null) {
if (launchOptions.ContainsKey(UIApplication.LaunchOptionsLocalNotificationKey))
isNotificationTapped = true;
}
LoadApplication(new App());
return base.FinishedLaunching(uiApplication, launchOptions);
}
When the user starts the app through notification tap, then FinishedLaunching method of AppDelegate is executed and we can validate the launchOptions dictionary to find the tap event, and if the app is in background or running stage , and user taps on the notification then the RecieveLocalNotification method of the AppDelegate is called.
public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification)
{
isNotificationTapped = true;
}
After initializing the value , I saved it in the UserDefaults using the DependencyService

monotouch remote control events not working

I would like to know if there is a working sample for monotouch that shows a working example for receiving remote control events such as those from the headphone buttons.
I have implemented a single view iphone app, implemented CanBecomeFirstResponder, called BecomeFirstResponder and also UIApplication.SharedApplication.BeginReceivingRemoteControlEvents() but I dont get any events.
Here is my code for my SingleViewController.
public partial class SingleViewViewController : UIViewController
{
public SingleViewViewController () : base ("SingleViewViewController", null)
{
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Perform any additional setup after loading the view, typically from a nib.
AVAudioSession audioSession = AVAudioSession.SharedInstance();
NSError error;
audioSession.SetCategory(AVAudioSession.CategoryPlayback, out error);
audioSession.SetActive(true,out error);
this.BecomeFirstResponder();
UIApplication.SharedApplication.BeginReceivingRemoteControlEvents();
}
public override void ViewDidUnload ()
{
base.ViewDidUnload ();
// Clear any references to subviews of the main view in order to
// allow the Garbage Collector to collect them sooner.
//
// e.g. myOutlet.Dispose (); myOutlet = null;
ReleaseDesignerOutlets ();
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
public override bool CanBecomeFirstResponder {
get {
return true;
}
}
public override bool CanResignFirstResponder {
get {
return false;
}
}
public override void RemoteControlReceived (UIEvent theEvent)
{
base.RemoteControlReceived (theEvent);
}
}
I spent a little bit of time on this and I think I might have an answer for you. My first faulty assumption was that the volume up and down controls on the remote (headphones) would register but they don't.
I haven't managed to confirm the following except through trial and error, but it appears that you need to have an AVAudioPlayer playing something, or at least playing something when you start the AVAudioSession. Without playing something the play / stop event gets passed to the Music app which handles it.
In your code, in the ViewDidLoad method after the call to base, I added
AVAudioPlayer player = new AVAudioPlayer(new NSUrl("Music/test.m4a", false), null);
player.PrepareToPlay();
player.Play();
If you look at chapter 27 of these samples on GitHub, you'll see an example that plays audio and handles the remote control events.
https://github.com/mattneub/Programming-iOS-Book-Examples
I wasn't able to get remote control events working without the player playing, your example matched lots of Obj-C samples but I couldn't make it work in Xcode either.
Hope this helps.

Resources