Search code examples
iosuiviewcontrollerxamarin.iosxamarin.formspresentviewcontroller

Warning: View is not in Window Hierarchy in Xamarin.Forms


I am doing a Xamarin project, Forms and I have integrated Xam.Plugins.Messaging to send SMS from my app. For this I have created a custom renderer in my iOS project with below code:

AppDelegate smsObj = new AppDelegate();
bool a= smsObj.ShowAndSendSMS(new string[] { "123" }, "Hi there");

And in my AppDelegate, I have the code as below:

public bool ShowAndSendSMS(string[] recipients, string body)
{
      UIViewController sms = new UIViewController();
      if (MFMessageComposeViewController.CanSendText)
      {
           MFMessageComposeViewController message = new MFMessageComposeViewController();
           message.Finished += (sender, e) => {
           message.DismissViewController(true, null);
      };
      message.Body = body;
      message.Recipients = recipients;
      sms.PresentModalViewController(message, false);
   }
   return true;
 }

The problem I am facing is on my first-time app launch, the functionality to share SMS doesn't work and the debug log gives me warning like "Attempt to present on whose view is not in the window hierarchy!"

However, if I restart the app, the same functionality works like a charm. Any ideas from where i have made mistake?


Solution

  • I think the problem is with the fact that you're newing up an AppDelegate and calling the ShowAndSendSMS from there. iOS is going to new up that AppDelegate for you upon app startup, and you should always use that, as opposed to creating a new instance of AppDelegate (at least I've never seen a situation that called for a multi-AppDelegate-instance pattern). So, try this:

    Create a helper class in your project like this (I don't really like the word "helper", but that's beside the point; name it something fitting for your project):

    using Foundation;
    using UIKit;
    
    public class SmsHelper
    {
        public bool ShowAndSendSMS(string[] recipients, string body)
        {
            if (MFMessageComposeViewController.CanSendText)
            {
                UIViewController sms = new UIViewController();
    
                MFMessageComposeViewController message = new MFMessageComposeViewController();
                message.Finished += (sender, e) => {
                    message.DismissViewController(true, null);
                };
                message.Body = body;
                message.Recipients = recipients;
                sms.PresentModalViewController(message, false);
            }
            return true;
        }  
    }
    

    And then change your page renderer to consume it like this:

    public class SMS_Ios: PageRenderer 
    {
        private readonly TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    
        protected override void OnElementChanged(VisualElementChangedEventArgs e) 
        {
            base.OnElementChanged(e);
    
            SmsHelper smsObj = new SmsHelper();
    
            bool a = smsObj.ShowAndSendSMS(new string[] {"123"}, "Hi there");
        }
    }
    

    And finally, remove ShowAndSendSMS from your AppDelegate.cs, since you'll be using your SMS helper going forward.

    Let me know if that works for you.