Introducing Suave Streams

Welcome to Suave Streams at https://twitch.tv/suave_pirate where I’ll be taking some time twice a week to build some of the coolest, funniest, and also innovative pieces of software using real-world patterns, practices, and tools.

Come for a laugh, come to build, and come to learn! We’ll be jumping into languages, and tools like:

  • C#
  • TypeScript
  • Kotlin
  • Swift
  • ASP.NET Core
  • Alexa Skills
  • Actions on Google
  • Bixby Capsules
  • Conversational AI
  • Real time communications
  • Xamarin/Maui.NET
  • UWP
  • Game Development
  • Bot building

and so much more!

We’re starting off with a schedule of every:

  • Sunday 12:30-4:30PM EST
  • Wednesday 6-10PM EST

I hope you’ll join for our first ever livestream this Sunday, May 22nd at 12:30pm EST where we are starting to build an Alexa Skill to Beat Call of Duty Warzone! Using:

C#, ASP.NET Core APIs, SignalR, UWP, Alexa Skills SDK, and scalable architectures and design patterns to make it come to life.

After each stream, I’ll also be uploading the whole recording (with minor edits) to my YouTube over at https://www.youtube.com/channel/UC1ycVqsWOInQuel68295M7w

So if you can’t make the stream, you won’t miss out on all the fun. Be sure to follow me on twitch for updates on when I go live and to keep up with the projects we start creating!

See you there!

 

 

Xamarin.Tip – iOS Push Notification Device Token Extraction in iOS 13+

This weekend, I spent some time getting some apps updated with the latest Xamarin, iOS, Android, etc. A lot of these apps make use of push notifications across platforms. I was running some automated tests against them to do the following steps:

  • Register for push notifications on sign-in / startup
  • Send registration update details to API
  • API sends updates to Azure Notification Hub or Firebase (depends on the project)
  • Send push notification to all test users
  • Send push notification to specific test user

I noticed immediately that all my new iOS builds were failing to receive any push notifications after updating registrations.

Time to debug!

The Old Way

Here was my original method for kicking off the push notification registration:

AppDelegate.cs

//...
private void RegisterForPush()
{
    if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
    {
        UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
            (granted, error) =>
            {
                if (granted)
                    InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications);
            });
    }
    else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
    {
        var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
                UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
                new NSSet());

        UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
        UIApplication.SharedApplication.RegisterForRemoteNotifications();
    }
    else
    {
        UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
        UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
    }
}
// ..

This processes kicks off the internal iOS process to start registration. It will check against your apps registered entitlements for push, check the environment it should be using between development and production, and then if all goes well, it will hit the RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken) method in the AppDelegate. If there are any explicit errors it will instead hit FailedToRegisterForRemoteNotifications(UIApplication application, NSError error).

So what we need is the data within that deviceToken of the RegisteredForRemoteNotifications method to send to our API.

Here is what the ORIGINAL implementation looked like (with some of the abstractions removed for simplicity):

AppDelegate.cs

// non-user registration
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    // if using default registration with notification hub for non-user apps
    Hub = new SBNotificationHub("{CONN_STRING}", "{AZURE_HUB_NAME}");

    Hub.UnregisterAll(deviceToken, (error) =>
    {
        if (error != null)
        {
            System.Diagnostics.Debug.WriteLine("Error calling Unregister: {0}", error.ToString());
            return;
        }

        NSSet tags = null; // create tags if you want
        Hub.RegisterNativeAsync(deviceToken, tags);

    });
}

And for handling specific user registration, we need to send it to the API:

AppDelegate.cs

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    var token = deviceToken?.Description?.Trim('<', '>')?.Replace(" ", string.Empty);
    if (!string.IsNullOrEmpty(token))
    {
        // this sends the handle to the API to do all the registration
        var remoteRegistrar = new RemoteNotificationRegistrar();
        remoteRegistrar.RegisterForPushAsync("apns", token);
    }
}

Debugging showed me the issue was here:

var token = deviceToken?.Description?.Trim('<', '>')?.Replace(" ", string.Empty);

The token was no longer in the same format… Feeling like an idiot who has been out of the loop, I hit the internet to see what I missed and landed on some of these lovely articles and posts:

So lets do this update in Xamarin:

The New Way

So the old token structure looked like this:

And the new token looks like this:

{length = 32, bytes = 0x965b251c 6cb1926d e3cb366f dfb16ddd ... 5f857679 376eab7c }

So basically we need a clean version of that bytes property of the NSData object.

Azure notification hubs already do this behind the scenes, but we need the clean version for our own method to send to our API, so here’s the new version:

AppDelegate.cs

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    var token = ExtractToken(deviceToken);
    if (!string.IsNullOrEmpty(token))
    {
        // this sends the handle to the API to do all the registration
        var remoteRegistrar = new RemoteNotificationRegistrar();
        remoteRegistrar.RegisterForPushAsync("apns", token);
    }
}

private string ExtractToken(NSData deviceToken)
{
    if (deviceToken.Length == 0)
        return null;
    var result = new byte[deviceToken.Length];
    System.Runtime.InteropServices.Marshal.Copy(deviceToken.Bytes, result, 0, (int)deviceToken.Length);
    return BitConverter.ToString(result).Replace("-", "");
}

There are a few different ways to write this ExtractToken method, but this is what has worked for me!.

After making this change and running it on iOS 13, I started getting user notifications again!

Both Ways

This is great and all, but I still want to make sure folks who haven’t updated to iOS 13 can still use my apps, so I added some explicit version checks to decide which way to extract the token. Here’s what the final looks like all within that ExtractToken method:

private string ExtractToken(NSData deviceToken)
{
    if(UIDevice.CurrentDevice.CheckSystemVersion(13,0))
    {
        if(deviceToken.Length > 0)
        {
            var result = new byte[deviceToken.Length];
            Marshal.Copy(deviceToken.Bytes, result, 0, (int)deviceToken.Length);
            return BitConverter.ToString(result).Replace("-", string.Empty);
        }
    }
    else 
    {
        return deviceToken?.Description?.Trim('<', '>')?.Replace(" ", string.Empty);
    }

    return null;
}

And that’s it! Try this out if you’re having issues with the latest iOS 13 update and your push notification registration.

If you’re still having problems with push notification registration in general, leave a comment below! I’d love to put together an article about the common pitfalls of push notifications on both iOS and Android with a checklist of things to look at, fix, or build on top of what you have!


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile and AI developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.


Xamarin.Tip – Fixing Missing iOS App Icons

In the age of Xamarin Hot Reload and Hot Restart, we are beginning to get spoiled with the tooling we use every day. I find myself spending less and less time dealing with workarounds for Xamarin issues, filing bug reports, or getting frustrated at not understanding why something isn’t working.

Until today…

The issue – I created an AppIcon for my iOS app, and it simply won’t show up on any device or simulator. I had seen this before, so I double checked everything and tried all my old tricks:

  • Check that the AppIcon asset was in the Assets.xcassets
  • Check that the actual AppIcon had all the images filled in
  • Check that my info.plist was pointing at my AppIcon
  • Clean
  • Rebuild
  • Clear all caches
  • Restart VS
  • Restart machine
  • Try on another machine, repeat above steps
  • Panic

Nothing. So, if you’re new to Xamarin development or iOS development in general, the above steps are definitely the first things to try!

One thing I did differently this time around was use https://makeappicon.com/ to generate my individual icons from a single high resolution image. Usually the designer on my team will send me the exact icons exported to the specific sizes, but they were on vacation and I wanted to make some progress! I 100% recommend using MakeAppIcon for those who haven’t discovered it yet.
For those that haven’t used it, MakeAppIcon gives you a zip with the actual AppIcon.appiconset which includes every size you need and their registration in the Contents.json which tells the build agent what images fit which profile/size. This Contents.json is also what Visual Studio uses to show you the icons in your Assets.xcassets.

So all you have to do is take the AppIcon.appiconset and drop it in your Assets.xcassets and you’re off and running. Or so I thought…

Turns out VS uses the Content.json to read the images to show in your assets, but this does not actually include them in any sort of build output to your final .ipa – so we need to actually update our ios project’s .csproj file to make sure all the images and their full paths are included – not just the AppIcon.appiconset. Normally, if you drag and drop or file select within Visual Studio to set the images for your app icon, this is done for you. But if you bring in your icons from any outside source, be sure to make sure you add them in the .csproj – something like this:

<ImageAsset Include="Assets.xcassets\AppIcons.appiconset\Contents.json">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Contents.json">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-20x20@1x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-20x20@2x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-20x20@3x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-29x29@1x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-29x29@2x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-29x29@3x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-40x40@1x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-40x40@2x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-40x40@3x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-60x60@2x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-20x20@1x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-60x60@3x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-76x76@1x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-76x76@2x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-83.5x83.5@2x.png">
  <Visible>false</Visible>
</ImageAsset>

Long story short – copy paste this into your .csproj if you use MakeAppIcon and save yourself some time. If this didn’t help you or isn’t why your App icon isn’t showing up, here are some links I’ve used in the past:
https://stackoverflow.com/questions/48375681/ios-app-icon-missing-on-ios-11
https://xamarin.github.io/bugzilla-archives/59/59515/bug.html
https://docs.microsoft.com/en-us/xamarin/ios/app-fundamentals/images-icons/app-store-icon
https://blog.rthand.com/post/2017/10/17/app-icons-missing-after-upgrading-to-ios-11-xamarin.aspx


More meaningful and useful content coming soon! Including more Alexa, Dialogflow, Google Assistant, Bixby, Cortana, and of course Xamarin work 🙂


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

HACKMIT 2019 This Weekend!

HackMIT is this weekend, September 14-15th.

I’m happy to announce that I’ll be mentoring as one of the local Microsoft MVPs that were invited to help as part of the Microsoft sponsorship of the event. I look forward to building some incredible applications with some of the brightest students coming to Cambridge! Hack for a reason 🙂

Check out some of the awesome tracks:

hackmit_tracks

 

If you’re hacking this weekend, come find me for help with:

  • Conversational AI
  • Voice First Development
  • Azure
  • AWS
  • Machine Learning
  • Unity
  • C#
  • JavaScript/TypeScript
  • Kotlin
  • React
  • Video Editing
  • and RTC

See ya’ll there!


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Tip – Build Your Own In-App Developer Options

This post is a continuation of building gesture based “easter eggs” into your Xamarin apps (native or Forms).

In this post, we are going to continue from these posts:
Xamarin.Tip – Add Easter Eggs to UWP with Key Combos
Xamarin.Tip – Add Easter Eggs on Shake

to talk about how we can use these gestures in Debug mode to give ourselves some shortcuts for testing and moving through our application quicker.

To breakdown the process setup – we added shake handlers (and keyboard shortcuts for UWP) that can invoke any contextual code in our application. We talked about using this for funny easter eggs, but this functionality can be made into something super useful for us.

I call this “Contextual Developer Options”. The idea is take that easter egg handler and use it to display some contextual options that can be controlled page by page or view by view. This can be toggling some UI updates, auto-navigating through the app, testing different scenarios, etc.

In this example we’ll be using MVVM and Xamarin.Forms to demonstrate the possibilities, but the same idea can be applied to any other pattern or practice. Basically we need to:

  • Register dev options to whatever context we want
  • Determine what context we are in
  • Display the actionable dev options

Before starting, I suggest looking at something like Allan Ritchie’s incredibly useful UserDialogs package https://github.com/aritchie/userdialogs

We’ll use it in our examples.

Setting Up Developer Options

First things first, let’s define our developer options.

DevelopmentOption.cs

public class DevelopmentOption
{
    public string Title { get; set; }
    public Action Action { get; set; }
}

Now, like I said, our example will be doing this in MVVM and we can use the current page the user is on as the context we want to apply.

I’ll start by creating a BasePageViewModel that we can use to set up our developer options and execute the action

BasePageViewModel.cs

public abstract class BasePageViewModel : ViewModelBase
{
    protected List<DevelopmentOption> _developerOptions;
    private bool _isShowingDeveloperOptions = false;

    public BasePageViewModel()
    {
        _developerOptions = new List<DevelopmentOptions>();
    }

    /// <summary>
    /// Shows the developer options. This should be called after a native easter egg such as a shake.
    /// </summary>
    public virtual async Task ShowDeveloperOptionsAsync()
    {
        if (_developerOptions.Any() && !_isShowingDeveloperOptions)
        {
            var titles = _developerOptions.Select(d => d.Title);
            _isShowingDeveloperOptions = true;
            var actionResult = await UserDialogs.Instance.ActionSheetAsync("Developer Options", "Cancel", null, null, titles.ToArray());
            _isShowingDeveloperOptions = false;
            // see if an option was selected
            if (titles.Contains(actionResult))
            {
                // call it if we find it.
                var option = _developerOptions.FirstOrDefault(d => d.Title == actionResult);
                option?.Action();
            }
        }
    }

    /// <summary>
    /// Sets up the developer options.
    /// </summary>
    protected virtual void SetupDeveloperOptions()
    {
        _developerOptions.Add(new DevelopmentOption()
        {
            Title = "Go to debug page",
            Action = () => UserDialogs.Instance.Toast("Not implemented")
        });
    }

    /// <summary>
    /// Adds the developer option.
    /// </summary>
    /// <param name="title">Title.</param>
    /// <param name="action">Action to perform when selected.</param>
    protected void AddDeveloperOption(string title, Action action)
    {
        _developerOptions.Add(new DevelopmentOption()
        {
            Title = title,
            Action = action
        });
    }
}

Alright let’s breakdown what’s going on here.

Our BasePageViewModel has a List that represents our different options for the given page. Then we have some protected methods we can use in our extended PageViewModels to setup different options.

In our SetupDeveloperOptions method, we can setup any option we want for the page, and we put a universal “Go to debug page” example action that is there on every page.

So here’s an example of a useful ViewModel that sets up a login page developer option.

LoginPageViewModel.cs

public class LoginPageViewModel : BasePageViewModel
{
    public string Email { get; set; }
    public string Password { get; set; }
    protected override void SetupDeveloperOptions()
    {
        AddDeveloperOption("Use test user", () => 
        {
            Email = "mytestuser@mydomain.com";
            Password = "myP@ssw0rd";
        });
    }
}

So what we want on this login page is to be able to shake the device and see the Action Sheet that shows “Use test user” and when selected, it should fill out the fields on the page automatically.

Now that our setup is done, let’s wire up accessing these developer options.

Wiring It Up

We need to be able to access our Page’s ViewModel in order to execute the developer options when the shake happens. To do this, we can access the current page via the Xamarin.Forms.Application.Current static accessor. Then use the MainPage property to get around.

I like to add a simple helper property getter on my App class for this:

App.xaml.cs

public class App : Application
{
    // ...

    // assuming MainPage is a NavigationPage. You can do some extra logic if it isn't
    public ContentPage CurrentPage => (MainPage as NavigationPage)?.Navigation?.NavigationStack?.Last()
    // ...
}

Now in our native app logic, where we were executing the easter egg we can call:

// we don't want developer options in production 🙂
#if DEBUG
await ((App.Current as App)?.CurrentPage?.BindingContext as BasePageViewModel)?.ShowDeveloperOptionsAsync();
#endif

So now if we are in our LoginPage and our BindingContext is set to our LoginPageViewModel, our shake should reveal the action sheet!

Conclusion

We can make our lives a whole lot easier when testing and running through our app by giving ourselves easier and contextual options throughout the entire application.

I’ve personally used this for some pretty awesome and intense stuff like:

  • Filling out forms with different values
  • Changing styles/themes of the app to easily compare 2 different UIs
  • Test different states of a page such as if a user is logged in or not
  • Test error scenarios
  • Build a page that shows logs of all interactions and background tasks in the app and use the developer options to navigate to that page whenever to see those custom logs live (even when not attached to the debugger)
  • Execute custom native code to make debugging easier
  • Navigate quickly to the page deep in the app I am currently working on

Remember to still write unit and UI tests for your app too! This is meant to be something to make real hands-on testing even easier too.

It has saved me hundreds of hours easily. Let me know if you end up implementing something like this too!

For now, I don’t have any complete open source project to demo this, but if enough of you want to see a full example and screenshots and different scenarios, I’ll consider putting a full project together. Let me know in the comments or on twitter!


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Tip – Adding a Password Toggle Button in iOS

In a previous post, we looked at how easy it was to add a Password Toggle button in our Xamarin.Android apps (or native Android since it was only in the xml layout): Xamarin.Tip – Adding a Password Toggle Button in Android

So in this post, let’s work toward a similar behavior in our Xamarin Native iOS!

The basic premise is to extend the UITextField control and add a SubView to it for the button. Then on this UIButton.TouchUpInside, we want to toggle the UITextField.SecureTextEntry boolean property.

With that in mind, there are a number of ways we can do this!

  • Create a custom PasswordToggleTextField and design it in a xib to drag and drop the button
  • Add the UIButton at runtime everywhere we want to use it
  • My Favorite: Use NativeBehaviors and create a reusable behavior that can be attached to any given UITextField.

Let’s continue down this path with the NativeBehaviors approach. Of course, if you don’t want to do it this way, you can simply copy the code within the Behavior we create and apply it anywhere else.

NativeBehaviors is a package I created just a little while back that brings the Xamarin.Forms style Behavior pattern to native iOS, Android, and UWP controls. So if you’ve written Xamarin.Forms Behaviors before, this should be super familiar!

Let’s do this by creating a simple TextFieldTogglePasswordBehavior.

TextFieldTogglePasswordBehavior.cs

/// <summary>
/// Text field toggle password behavior.
/// </summary>
public class TextFieldTogglePasswordBehavior : NativeBehavior<UITextField>
{
    public override string BehaviorName => nameof(TextFieldTogglePasswordBehavior);

    private UIButton _togglePasswordButton;

    /// <summary>
    /// Attach show/hide button
    /// </summary>
    /// <param name="bindable">Bindable.</param>
    protected override void OnAttachedTo(UITextField bindable)
    {
        _togglePasswordButton = new UIButton()
        {
            Frame = new CGRect(0, 0, 50, 8)
        };

        _togglePasswordButton.SetTitle(bindable.SecureTextEntry ? "Show" : "Hide", UIControlState.Normal);
        _togglePasswordButton.SetTitleColor(UIColor.White, UIControlState.Normal);
        _togglePasswordButton.SetAttributedTitle(new Foundation.NSAttributedString(bindable.SecureTextEntry ? "Show" : "Hide", UIFont.SystemFontOfSize(12)), UIControlState.Normal);
        _togglePasswordButton.TouchUpInside += (sender, e) =>
        {
            var updatedIsPassword = !bindable.SecureTextEntry;
            bindable.SecureTextEntry = updatedIsPassword;
            _togglePasswordButton.SetTitle(updatedIsPassword ? "Show" : "Hide", UIControlState.Normal);
            _togglePasswordButton.SetAttributedTitle(new Foundation.NSAttributedString(updatedIsPassword ? "Show" : "Hide", UIFont.SystemFontOfSize(12)), UIControlState.Normal);
        };
        _togglePasswordButton.TitleLabel.TextColor = UIColor.White;
        bindable.RightViewMode = UITextFieldViewMode.Always;
        bindable.RightView = _togglePasswordButton;
        bindable.RightViewRect(new CGRect(0,0, 50,8));
    }

    /// <summary>
    /// Kill the button
    /// </summary>
    /// <param name="bindable">Bindable.</param>
    protected override void OnDetachingFrom(UITextField bindable)
    {
        _togglePasswordButton = null;
        bindable.RightView = null;
    }
}

If you read through the code a bit, you noticed that we simply create a UIButton, set its text to UIColor.White, and then update the text of the button to either “Show” or “Hide” depending on the state, and then in the TouchUpInside handler, we update that state as well as the SecureTextEntry property of the parent UITextField this behavior gets attached to!

You can also update this to use icons instead of regular text buttons to get a behavior closer to the Android treatment if you wanted. It’s just a button, so go crazy.

Now let’s take this behavior and attach it to an existing UITextField control that we have added to a UIViewController in our Storyboard.

In this example, I’m using a custom UITextField called MaterialTextField to show that this behavior is usable on the built in controls as well as any other custom UITextField:

LoginViewController.cs

public class LoginViewController : UIViewController 
{
    // note: this is now reusable if you want to apply the behavior to multiple fields
    // without creating a bunch of new instances.
    private readonly TextFieldTogglePasswordBehavior _togglePasswordBehavior = new TextFieldTogglePasswordBehavior();

    protected void ViewDidLoad() 
    {
        PasswordTextField.AttachBehavior(_togglePasswordBehavior);
    }
}

And that’s it! If we want to remove the button and detach the behavior, all we have to do is call:

PasswordTextField.DetachBehavior(_togglePasswordBehavior);

With all that together, we get a pretty neat control!

Screen Shot 2018-03-15 at 11.04.00 AMScreen Shot 2018-03-15 at 11.03.54 AM

In a future post, we can look at how to achieve this same concept in Xamarin.Forms – without using custom renderers!


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Tip – Embed Your Xamarin.Forms Pages in Your iOS ViewControllers

The number one complaint I hear about Xamarin.Forms is the slow startup time of the applications that use it. The team at Xamarin has done a lot to help with this and give some more options such as XAML Compilation, Lazy Loading, and Ahead of Time Compilation. Check out some of David Ortinau’s suggestions here: 5 Ways to Boost Xamarin.Forms App Startup Time.

However, one of the best ways I’ve found to help with this issue is to use Xamarin.Forms Embedding to its full potential. Embedding became available in Xamarin.Forms 2.5 and at a high level allows you to embed your Xamarin.Forms pages into your Native Xamarin views by using the extension methods .CreateFragment(Context context); for Android and .CreateViewController(); for iOS. This is most commonly used for when you want to share some UI in your Xamarin Native apps using Xamarin.Forms, however you still need to call Xamarin.Forms.Init() which is one of the main culprits in the slow startup time.

For Android embedding, see: Xamarin.Tip – Embed Your Xamarin.Forms Pages in Your Android Activities

iOS

The solution proposed here still allows you to create almost all of your views in Xamarin.Forms by using embedding, but requires some architecture and design changes. The premise is this:

  • First ViewController is non-Xamarin.Forms and loads your app right away
  • Init Xamarin.Forms after this ViewController is loaded
  • Embed Xamarin.Forms pages in other ViewControllers
  • Lift navigation out of Xamarin.Forms and into the native navigation.

This also has advantages outside the startup time such as better performance on transitions, more natural look and feel to end-users, performance gains in other areas, and a smaller app-size.

This means:

  • No NavigationPage
  • No Xamarin.Forms toolbar (using the native UINavigationBar control instead)
  • Still have MVVM and all our bindings we would expect

So if you’re already using a framework that is not tied down to Xamarin.Forms such as MvvmLight, you don’t have to change much behind the scenes since the INavigationService is abstracted.

Let’s kick this off by creating an inheritable ViewController that handles the embedding and layout how we want. Be sure to use your Storyboard and have the RootViewController be a UINavigationController, then use this embeddable ViewController within that.

XamarinFormsViewController

/// <summary>
/// Base xamarin forms view controller. Used for embedding a Xamarin.Forms page within a native view controller.
/// When inheriting from this, be sure to create a ViewController within the storyboard as well so that navigation
/// can properly work.
/// </summary>
public abstract class XamarinFormsViewController<TPage> : UIViewController
    where TPage : ContentPage, new()
{
    protected TPage _page;


    public XamarinFormsViewController(IntPtr handle) : base(handle)
    {
    }

    /// <summary>
    /// Load the Xamarin.Forms Page's ViewController into the parent
    /// </summary>
    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        _page = new TPage();
        var xamarinFormsController = _page.CreateViewController();
        AddChildViewController(xamarinFormsController);
        View.AddSubview(xamarinFormsController.View);
        xamarinFormsController.DidMoveToParentViewController(this);

        // add whatever other settings you want - ex:
        EdgesForExtendedLayout = UIKit.UIRectEdge.None;
        ExtendedLayoutIncludesOpaqueBars = false;
        AutomaticallyAdjustsScrollViewInsets = false;

    }
}

When creating a child of this XamarinFormsViewController, be sure to also create an empty ViewController in your .storyboard file for each unique type. This is required for handling navigation using the storyboard and root UINavigationViewController. If you’re using .xib files for some reason, then don’t worry about it, just instantiate the XamarinFormsViewController itself (you’ll have to add the other constructor overloads though).

So now we can create a simple Xamarin.Forms page:

SomePage.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"     x:Class="MyApp.Pages.SomePage">
    <ContentPage.Content>
        <Grid>
            <Label Text="I'm Embedded!" HorizontalOptions="Center" VerticalOptions="Center"/>
        </Grid>
    </ContentPage.Content>
</ContentPage>

Then create the associated ViewController:

SomeViewController.cs

public class SomeViewController: XamarinFormsViewController<SomePage>
{
    protected void ViewDidLoad()
    {
        base.ViewDidLoad();

        NavigationItem.Title = "Some title";
    }
}

Now all we have to do is kick off this SomeViewController after calling Xamarin.Forms.Init() and we are good to go! If we have a MainController we can call it before navigating if it isn’t initialized, or execute it in ViewDidLoad or a similar lifecycle event.

MainController.cs

public class MainController: UIViewController
{    

    protected override void ViewDidLoad()
    {
        base.ViewDidLoad();

        // assume SomeButton is created and named in the Storyboard file
        SomeButton.TouchUpInside += delegate 
        {
             if(!Xamarin.Forms.Forms.IsInitialized)
                 Xamarin.Forms.Forms.Init(this, savedInstance);

             var someController = this.Storyboard.InstantiateViewController("SomeController") as SomeViewController;
             NavigationController.PushViewController(someController, true);
        }
    } 
}

And there you have it! Some new Xamarin.Forms embedding for performance and other extra benefits 🙂

In future posts of this subject, we’ll look at extending interactions between the Xamarin.Forms Page and the native Activity and ViewControllers, using advanced native components with the embedded Xamarin.Forms Page, and more!

Let me know what you think of this pattern – have you used it? What else would you want to hear about it??

Be sure to checkout some of the Xamarin examples on embedding too!


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.