Setup Your Mac for Development with Xamarin

If you are building with Xamarin.iOS, you'll need to connect your Visual Studio to your Mac as the build server. If you don't connect your PC to your Mac, you can't even open the Storyboard file nor run your build on an emulator or iPhone.

Here are the steps

Buy/Steal a Mac if you don't have one.

Turn on your Mac.

Click on the Apple icon at the top left, click About This Mac. Make sure the version is 10.12 Sierra (this is the version this tutorial is written based on, you can try any newer builds later but I don't know if it'll work). If it's not, update it to 10.12 Sierra. You can update it by clicking on the Apple icon > App Store > Updates. If you don't do this, the Xamarin Mac Agent will not be able to connect to your Mac because reasons.

Version is good? Now there are 2 things you'll need to install and update.

Install XCode 8.3 or above. You can do that by clicking on the Apple > App Store > Search for XCode. Install it.

Install Visual Studio for Mac. You'll need to download it at https://www.visualstudio.com/ using your Mac. More detailed steps here: https://docs.microsoft.com/en-us/visualstudio/mac/installation

Done all that? Nice. Now you need your Mac's IP. Click on the Wifi icon somewhere on the top right. Right Click > Open Network Preferences. Take note of the IP Address.

Awesome. Now go back to your darling PC. Go to Tools > iOS > Xamarin Mac Agent.

You can follow the instructions on the screen. But I'll walk you through anyways.

On your mac, open Spotlight (press Cmd+Space), search for Remote Login, open the Sharing System Preferences.

Enable the "Remote Login" option.

Select Allow Access for Only These Users. Make sure your user is in the list.

Get your Mac's username and password. Note that what you always see on your Mac is the display name. If you don't remember the username, open spotlight (cmd + space), type terminal, open terminal. Use " ls /users " to get a list of users and guess your username from there.

Now back to your PC. Click 'Next'. You'll reach the Xamarin Mac Agent selection page.

Now this is important. Click the Add Mac... button and fill in your Mac's IP Address. Do NOT click on anything in the list. At the time of writing, there may be a bug where the Mac agent simply refuses to connect to Visual Studio when you create a Storyboard later, or maybe I'm just stupid, but anyways do not select from the list. Fill in your IP Address manually in the Add Mac... dialog. Click enter. And after it has finished refreshing, THEN click on your IP in the list.

Now it's going to ask for your Username and Password. Fill it in. Make sure your Mac screen is on and not in sleep mode.

Everything okay? Alright, give yourself a pat on the back. You've earned it.

Enable Developer Mode on Android

To enable developer mode on Android:

  1. Go to Settings > About Phone > Build Number
  2. Tap on the Build Number 7 times. You will get the message "You are now a developer!"
  3. Go back to Settings. Look for Developer Options. Turn it on and also turn on USB Debugging.

Now that you're done, if you're using Visual Studio, simply plug your Android in. You phone will now be available as a debug option.

Xamarin.Native Tutorial: InvoiceJe

Alright, so today we'll be doing a Xamarin.Native tutorial, of which we will be writing an application from scratch to being able to do SQLite database transactions.

This tutorial will be pretty detailed, in which we'll make an app which you can proudly upload to the app store ;). Or at least, it'll give you all you need to know from scratch until you can make a deployable app.

The final app will hopefully look like this:

Mockup made using MarvelApp. I highly recommend them!

Basic Requirements

Of course, to follow this tutorial, you'll need a few things:

The good thing is, that's it! Of course, if you don't have a Mac that might pose a problem.

New Project

First up, let's create a new Xamarin.Native project.

Boot up your Visual Studio 2017. Click File > New Project.

Choose Visual C# > Cross-Platform > Cross Platform App (Xamarin), as per depicted in the screenshot below. Name the project InvoiceJe.

Click OK. Now you'll encounter this dialog:

For our purpose, choose Blank App, Native and Portable Class Library (PCL). Click OK.

You will get another dialog asking for the target and minimum platform versions for the Universal Windows Platform app.

Simply choose the default and click 'OK'.

Cool, now you're all set up. Your Solution tree will look like this.

 

Now, the Portable Class Library represents code that is shared across all platforms. The Android, iOS and UWP obviously represents code for each platform respectively.

Feel free to divide however you want, but usually we'll put all the business logic codes inside the portable class library and the UI ones inside each platform (though sometimes things get hairy inside the UI codes, but that's a problem for another day).

Try Running Each App

Alright, for now let's try running each project.

Universal Windows Platform

Let's try with Universal Windows Project. This is easy because we can simply run it on our machine. 

The methodology is: Deploy -> Run.

First, make sure you've selected InvoiceJe.UWP as the Startup Project and set it to deploy on the Local Machine at the top bar.

In the solution explorer, Right-Click on InvoiceJe.UWP and click Deploy. This will deploy the UWP on the local machine.

Next, click the Play button at the top bar. Your UWP app will now run.

You can also run your app on Windows phone by setting it to Developer Mode. Then simply plug it in and change from Local Machine to your phone.

Android

For Android, I prefer using my Android phone.

First you'll need to set it to Developer Mode.

Next, you'll need to install Android Debug Bridge (ADB) USB Driver if you're unlucky (and in Android development, you are always unlucky).

Download and install it here: https://software.intel.com/protected-download/385047/494732

(The full article about it is here, but just download the driver at the above link and install it)

Now, after installing the ADB driver, plug your Android in. Your Android will now be a choice.

Your phone will now be in the toolbar. Change the Play Button from deploying into the Emulator to your phone.

Now, Right-Click on InvoiceJe.Android and click Deploy. Then, click the Play button. Yay!

iOS

iOS will be a bit involved because you need to Setup your Mac for Development with Xamarin first.

Once you have Setup your Mac, at the Play button, change it to your desired emulator (iPhone/iPad) and then simply click the Play button. 

Alright, so did you manage all of them? Alright, so our next plaything will be Android. So, let's go!

Table of Contents

No Database

UWP: http://miaw.xyz/b/post/2017/07/19/xamarin-native-tutorial-invoiceje-universal-windows-platform

Android: http://miaw.xyz/b/post/2017/07/12/xamarin-native-tutorial-invoiceje-android

iOS: http://miaw.xyz/b/post/2017/07/14/xamarin-native-tutorial-invoiceje-ios

Databinding No Database

Databinding Setup (DO THIS FIRST BEFORE PROCEEDING FURTHER DOWN THE LIST)http://miaw.xyz/b/post/2017/07/25/xamarin-native-tutorial-invoiceje-databinding-setup

UWP: http://miaw.xyz/b/post/2017/08/02/xamarin-native-tutorial-invoiceje-databinding-universal-windows-platform

Android: http://miaw.xyz/b/post/2017/07/25/xamarin-native-tutorial-invoiceje-databinding-android

iOS: http://miaw.xyz/b/post/2017/07/26/xamarin-native-tutorial-invoiceje-databinding-ios

Databinding with Database

Setup EntityFramework and SQLite: http://miaw.xyz/b/post/2017/08/03/xamarin-native-tutorial-invoiceje-sqlite-database (DO THIS FIRST BEFORE PROCEEDING FURTHER DOWN THE LIST)

UWP: In progress

Android: In progress

iOS: In progress

(But I'm pretty sure you have already realized that you simply need to replace the methods inside RabbitService to call the database instead. And yeah you may need to refresh your screens)

Consuming RESTful Webservice + Animations

Setup: http://miaw.xyz/b/post/2017/09/20/xamarin-native-tutorial-consuming-webservice-setup (DO THIS FIRST BEFORE PROCEEDING FURTHER DOWN THE LIST)

 UWP: In Progress

Android: http://miaw.xyz/b/post/2017/09/20/xamarin-native-tutorial-consuming-webservice-android

 

iOS: In progress  

 

 

MVVMCross not calling Initialize() in ViewModel called from RegisterAppStart() in App.cs

MVVMCross 5.0.6 not calling Initialize() in ViewModel called from RegisterAppStart() in App.cs

https://github.com/MvvmCross/MvvmCross/issues/1972

The problem is that the underlying RegisterAppStart uses ShowViewModel() rather than  the new MvxNavigation.

The solution: Implement a custom AppStart that uses the NavigationService instead of ShowViewModel().

public class CustomAppStart : IMvxAppStart
    {
        private readonly IMvxNavigationService _navigationService;

        public CustomAppStart(IMvxNavigationService navigationService)
        {
            _navigationService = navigationService;
        }

        public void Start(object hint = null)
        {
            try
            {
                _navigationService.Navigate<MainViewModel>().GetAwaiter().GetResult();
            }
            catch
            {
            }
        }
    }

...And your Setup.cs should be edited to use the CustomAppStart, like this: 

 public class App : MvvmCross.Core.ViewModels.MvxApplication
    {
        public override void Initialize()
        {
            CreatableTypes()
                .EndingWith("Service")
                .AsInterfaces()
                .RegisterAsLazySingleton();

            // custom app start
            Mvx.ConstructAndRegisterSingleton<IMvxAppStart, CustomAppStart>();
            var customAppStart = Mvx.Resolve<IMvxAppStart>();

            RegisterAppStart(customAppStart);
        }
    }

 

 

FZ2CL: InvoiceJe: iOS

Let's start with the iOS implementation.

Setup

First things first:

If you followed the previous tutorial, you'll need to inherit the AppDelegate class from MvxApplicationDelegate (as per outlined in the TipCalc tutorial, the Nuget didn't help up update this part :( ). 

Next, you'll need to override the FinishedLaunching function to this:

 public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
        {
            // Override point for customization after application launch.
            // If not required for your application you can safely delete this method
            Window = new UIWindow(UIScreen.MainScreen.Bounds);

            var presenter = new MvxIosViewPresenter(this, Window);

            var setup = new Setup(this, presenter);
            setup.Initialize();

            var startup = Mvx.Resolve<IMvxAppStart>();
            startup.Start();

            Window.MakeKeyAndVisible();

            return true;
        }

Once you've done the above, let's start adding the MainView, ConfigurationView and InvoicesView. Simply Right Click -> Add Class and add a StoryboardViewController for each of the 3 views. Remember to  add a ViewController to each Storyboard and change the class and storyboardId to each respective MainView, ConfigurationView and InvoicesView.

And for each MainView, ConfigurationView and InvoicesView, add the [MvxFromStoryboard] attribute to the class.

Okay, just so we can differentiate between ConfigurationView and InvoicesView when we switch tabs, at each storyboard, add a label with the text 'Configuration' and 'Invoices' respectively.

Alright with that out of the way, we can start actually implementing the TabBar.

MvxIosPresenter

In MvvmCross5, they have added a new default presenter which makes our life a whole lot easier in implementing the default navigation methods (tabbar, stack and modal). Right now, we'll be playing around with the TabBar. More info can be found at MvvmCross' documentation.

Set Root Presentation

Just like in the Android project, our MainView will be our Root.

So in MainView.cs, add the [MvxRootPresentation] attribute.

And since InvoicesView and ConfigurationView will be our tabs, then:

Add [MvxTabPresentation(TabName = "Configuration")] to ConfigurationView

Add [MvxTabPresentation(TabName = "Invoices")] to InvoicesView

That's it. We're done! Well, not so.

If you try to run the app, you'll only get a blank screen.

This ViewPresenter have a gotcha, which isn't very intuitive, in which we NEED to call the ShowViewModel() method to each child views before the root view will show the links to each child views in the tab bar.

Hence, let's do that.

Inside the MainViewModel(), let's add the function ShowInitialViewModelsCommand() that will be used by our root view, like so:

        private IMvxCommand _showInitialViewModelsCommand;
        public IMvxCommand ShowInitialViewModelsCommand
        {
            get
            {
                return _showInitialViewModelsCommand ?? (_showInitialViewModelsCommand = new MvxCommand(ShowInitialViewModels));
            }
        }
        private void ShowInitialViewModels()
        {
            ShowViewModel<InvoicesViewModel>();
            ShowViewModel<ConfigurationViewModel>();
        }

...And in our MainView.cs, let's override the ViewWillAppear method and trigger the ShowInitialViewModelsCommand. We'll add a bit more functionality so that the command will only be triggered at the first time the view is seen by the user.

        private bool _isPresentedFirstTime = true;

        public override void ViewWillAppear(bool animated)
        {
            base.ViewWillAppear(animated);

            if (ViewModel != null && _isPresentedFirstTime)
            {
                _isPresentedFirstTime = false;
                ViewModel.ShowInitialViewModelsCommand.Execute(null);
            }

        }

 

Now that we're done, try running your iOS app again. It should work this time :)

Adding a divider to recycler view

There are two ways:

One would be to simply add an empty view with a 12% black background to the end of each item in RecyclerView. Like this:

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/customDividerColor"/>

The other way would be to define the ItemDecoration in the RecyclerView, as per outlined in this StackOverflow question:

https://stackoverflow.com/questions/31242812/how-can-a-divider-line-be-added-in-an-android-recyclerview

 

The elements you can override in Theme.AppCompat

ref: https://stackoverflow.com/questions/26702000/change-status-bar-color-with-appcompat-actionbaractivity

<!-- ============= -->
<!-- Color palette --> <!-- ============= --> <!-- The primary branding color for the app. By default, this is the color applied to the action bar background. --> <attr name="colorPrimary" format="color" /> <!-- Dark variant of the primary branding color. By default, this is the color applied to the status bar (via statusBarColor) and navigation bar (via navigationBarColor). --> <attr name="colorPrimaryDark" format="color" /> <!-- Bright complement to the primary branding color. By default, this is the color applied to framework controls (via colorControlActivated). --> <attr name="colorAccent" format="color" /> <!-- The color applied to framework controls in their normal state. --> <attr name="colorControlNormal" format="color" /> <!-- The color applied to framework controls in their activated (ex. checked) state. --> <attr name="colorControlActivated" format="color" /> <!-- The color applied to framework control highlights (ex. ripples, list selectors). --> <attr name="colorControlHighlight" format="color" /> <!-- The color applied to framework buttons in their normal state. --> <attr name="colorButtonNormal" format="color" /> <!-- The color applied to framework switch thumbs in their normal state. --> <attr name="colorSwitchThumbNormal" format="color" />