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.
Related
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
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?
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);
}
}
I have successfully connected a steel series Nimbus dual analog controller to use for testing in both my iOS and tvOS apps. But I am unsure about how to properly set up the valueChangeHandler portion of my GCController property.
I understand so far that there are microGamepad, gamepad and extendedGamepad classes of controllers and the differences between them. I also understand that you can check to see if the respective controller class is available on the controller connected to your device.
But now I am having trouble setting up valueChangeHandler because if I set the three valueChangeHandler portions like so, then only the valueChangeHandler that works is the last one that was loaded in this sequence:
self.gameController = GCController.controllers()[0]
self.gameController.extendedGamepad?.valueChangedHandler = { (gamepad, element) -> Void in
if element == self.gameController.extendedGamepad?.leftThumbstick {
//Never gets called
}
}
self.gameController.gamepad?.valueChangedHandler = { (gamepad, element) -> Void in
if element == self.gameController.gamepad?.dpad {
//Never gets called
}
}
self.gameController.microGamepad?.valueChangedHandler = { (gamepad, element) -> Void in
if element == self.gameController.microGamepad?.dpad {
//Gets called
}
}
If I switch them around and call self.gameController.extendedGamepad.valueChangeHandler... last, then those methods will work and the gamepad and microGamepad methods will not.
Anyone know how to fix this?
You test which profile is available and depending on the profile, you set the valueChangedHandler.
It's important to realise that the extendedGamepad contains most functionality and the microGamepad least (I think the microGamepad is only used for the AppleTV remote). Therefore the checks should be ordered differently. An extendedGamepad has all functionality of the microGamepad + additional controls so in your code the method would always enter the microGamepad profile.
Apple uses the following code in the DemoBots example project:
private func registerMovementEvents() {
/// An analog movement handler for D-pads and movement thumbsticks.
let movementHandler: GCControllerDirectionPadValueChangedHandler = { [unowned self] _, xValue, yValue in
// Code to handle movement here ...
}
#if os(tvOS)
// `GCMicroGamepad` D-pad handler.
if let microGamepad = gameController.microGamepad {
// Allow the gamepad to handle transposing D-pad values when rotating the controller.
microGamepad.allowsRotation = true
microGamepad.dpad.valueChangedHandler = movementHandler
}
#endif
// `GCGamepad` D-pad handler.
// Will never enter here in case of AppleTV remote as the AppleTV remote is a microGamepad
if let gamepad = gameController.gamepad {
gamepad.dpad.valueChangedHandler = movementHandler
}
// `GCExtendedGamepad` left thumbstick.
if let extendedGamepad = gameController.extendedGamepad {
extendedGamepad.leftThumbstick.valueChangedHandler = movementHandler
}
}
I am trying to embed a webview into navController, but end up with webview not scrollable at all.
The webpage regardless of its size will not allow to be scrolled. What am I doing wrong here?
using Foundation;
using UIKit;
using System.Drawing;
namespace TestNamespace
{
public class Level2ViewController : UIViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
Title = "Test";
UIWebView webview = new UIWebView (View.Bounds);
View.AddSubview(webview);
webview.LoadRequest (new NSUrlRequest (new NSUrl("https://news.google.com/")));
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
}
}
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to application events from iOS.
[Register ("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
// class-level declarations
UIWindow window;
UINavigationController navController;
public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
window = new UIWindow ();
window.MakeKeyAndVisible ();
navController = new UINavigationController ();
Level2ViewController new1 = new Level2ViewController();
// push the view controller onto the nav controller and show the window
navController.PushViewController(new1, false);
window.RootViewController = navController;
window.MakeKeyAndVisible ();
return true;
}
public override void OnResignActivation (UIApplication application)
{
// Invoked when the application is about to move from active to inactive state.
// This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message)
// or when the user quits the application and it begins the transition to the background state.
// Games should use this method to pause the game.
}
public override void DidEnterBackground (UIApplication application)
{
// Use this method to release shared resources, save user data, invalidate timers and store the application state.
// If your application supports background exection this method is called instead of WillTerminate when the user quits.
}
public override void WillEnterForeground (UIApplication application)
{
// Called as part of the transiton from background to active state.
// Here you can undo many of the changes made on entering the background.
}
public override void OnActivated (UIApplication application)
{
// Restart any tasks that were paused (or not yet started) while the application was inactive.
// If the application was previously in the background, optionally refresh the user interface.
}
public override void WillTerminate (UIApplication application)
{
// Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground.
}
}
}
Write this in ViewDidLoad
webiew.ScrollView.ScrollEnabled = true;
webView.ScalesPageToFit = true;