I’m a software developer in London UK, creating Apps with Xamarin and these are my thoughts based on my day to day experiences developing with it. Need a contractor for Xamarin (offsite) or onsite in London or C#? Contact Me.

(August 2014)
I’m just coming up to complete my first App which uses multi-threading, TCP/IP and runs very responsively on an iPhone 4! It’s for Taxi drivers and uses a propietary packet protocol to talk to a server over a TCP/IP port.

This was a simple app that lets the user scan a bar-code, take a photo then upload both the photo and bar-code to a website, it was an interesting first app.

Coming from the world of Xamarin iOS development there was a bit of culture shock with Activities and Fragments compared to view controllers. Plus if you want to access a form control you have to find it. Every control ends up as a constant in a large compiler generated file Resource.Designer.cs and to use objects mapped to them you need code like this. The controls objects are declared elsewhere.

            
            ScanButton = FindViewById<Button>(Resource.Id.barcodeButton);
            Barcode = FindViewById<TextView>(Resource.Id.barcode);
            StatusView = FindViewById<TextView>(Resource.Id.status);
            ImageView = FindViewById<ImageView>(Resource.Id.imageView1);
            PhotoButton = FindViewById<Button>(Resource.Id.photoButton);
            UploadButton = FindViewById<Button>(Resource.Id.uploadButton);
            SettingsButton = FindViewById<ImageButton>(Resource.Id.settingsButton);

Scanning Barcodes

The first big problem was bar-code scanning but the excellent open source Apache Licensed Zxing mobile barcode scanner component solved that. Tips for working with that, get a 5″ screen phone and scan under good light. I’m very impressed with that.

Taking a photo wasn’t rocket science, there’s plenty of source for that around. But photos that are large (typically 3,000 x 2,000 pixels) need to be reduced and converted. I set a maximum largest dimension of 750 and ran this loop to calculate the new size.

                
                float height = App.Height;
                float width = App.Width;
                float ratio = height/width;
                while (height > 750 || width > 750)
                {
                    height -= 100;
                    width = height/ratio;
                }

then this code to rescale the bitmap and compress to a jpg with a quality of 80.

                
                var reducedBitmap = Bitmap.CreateScaledBitmap(App.bitmap, (int)width, (int)height,false);
                StatusView.Text = "Processing Image";
                var stream = new MemoryStream();
                reducedBitmap.Compress(Bitmap.CompressFormat.Jpeg, 80, stream);
                var bitmapData = stream.ToArray();

Leaving me with an array of bytes to upload. Sending a string and an image together in one http post is a little bit harder. Here’s how I did it. I found Brian Grinstead’s post and used his FormUpload class.

                var postParameters = new Dictionary<string, object>();
                postParameters.Add("barcode", Barcode.Text);
                postParameters.Add("file", new FormUpload.FileParameter(bitmapData, "image.jpg", "image/jpg"));

                // Create request and receive response
                var postURL = UploadUrl;
                var userAgent = "Someone";
                var webResponse = FormUpload.MultipartFormDataPost(postURL, userAgent, postParameters);

As easy as that!

XML

Unless you want to write it in code, you’ll find that you use XML for lots of things- the Android Manifest file, the layout of each form, strings, styles and preferences. Plus if you are targetting specific versions, screen sizes, you’ll have versions for that as well. It can add up to a lot of XML files. The layout alone is 65 lines long for just three buttons, one image button, one image view plus a couple of labels.

Screen shot of App

Debugging on Android

You have a choice of running the Xamarin simulator in VirtualBox which is ok but doesn’t really work well for scanning barcodes or taking photos so I found the USB device drivers for two handsets I had and debugged on the phones. For some phones the drivers are easy to find, others not so. Once they’re installed, ADB (Android Debug Bridge) is your friend to get going and after that just plug the phone in and Xamarin picks it up.

I found a slight bug and I’m not sure if it’s Xamarin or the phone’s drivers. I’d make a change do a rebuild and deploy and even though it said the previous version was removed it ran the previous version. Uninstalling the App fixed that but it only happened on three occasions so not a big deal.

Distribution

This wasn’t for the Google Play store but a private client. All I had to do was build for Release then click Export Android Package on the build menu. That creates two .apk files and I uploaded the one that had signed in its name.

Did you know that an .apk file like a java .jar file is actually a zip file? Just rename the extension to .zip and you can see everything in it. Note that the XML files may be XML binary files but there are tools to convert them to text XML files.

I’ve been converting a major App and the Migrate tool works very well but I found a couple of cases, which either it didn’t do or I messed up.

The first is when using a nint as an index in a List. It doesn’t work, as the .NET generics know nothing about nints. So just cast it to an int like this below where _itemsList is a List

Text = _itemsList[(int)row];

Converting NSDate to System.DateTime and vice versa

It’s now a compile error to assign a DateTime to a NSDate or vice versa, the implicit conversion no longer works. I think this is to highlight a subtle bug to do with NSDate is always an UTC time and DateTime is default set to DateTimeKind.Unspecified (when read from database) or DateTimeKind.Locale (when set with DateTime.Today) Source is this stackoverflow answer.

Thankfully the Foundation.NSDate class includes two explicit operators that do the job for you.
NSDate in Xamarin Object Browser


So this works.

            NSDate nDate = (NSDate) DateTime.Now;
            DateTime dDate = (DateTime) nDate;

AVAudioRecorder Changes

The settings used to create an AVAudioRecorder have changed from a NSDictionary to AudioSettings, and the AVAudioRecorder.ToUrl method no longer exists.

Instead create avsettings like this and use the factory method Create to create the AVAudioRecorder.

//Set Settings with the Values and Keys to create the NSDictionary
            avsettings = new AudioSettings(NSDictionary.FromObjectsAndKeys(values, keys));

//Set recorder parameters
            recorder = AVAudioRecorder.Create(url, avsettings, out error);

It’s kind of obvious in retrospect about enabling or disabling animation. It’s part of some code where I’ve added a UIImage onto a MkMapView (Apple’s iOS Controls for displaying a map), that centres the map on your current location when you click it. The button is a gun sight type icon and I’ve located in the bottom right edge of the map.

    private UIButton btnCurrentLoc; // defined at the class level

// in ViewDidLoad
    var ImageCurrentLoc = UIImage.FromBundle("images/currentloc.png");
    ImageCurrentLoc.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);

    btnCurrentLoc = new UIButton() { TintColor = UIColor.Black };
    btnCurrentLoc.SetImage(ImageCurrentLoc, UIControlState.Normal);
    btnCurrentLoc.Frame = new RectangleF(View.Frame.Width-50, View.Frame.Height - 100, ImageCurrentLoc.Size.Width, ImageCurrentLoc.Size.Height);

    btnCurrentLoc.TouchUpInside += (s, e) =>
                {
                    map.SetCenterCoordinate(map.UserLocation.Location.Coordinate,true);  // animated
                    //map.CenterCoordinate = map.UserLocation.Location.Coordinate;       // not animated, moves directly            
                }; 

  View.AddSubview(map);            // has to be this way round! map first then control
  View.AddSubview(btnCurrentLoc);

Note that you add the map first to the view then the button.

As it’s commented if you click the btnCurrentLoc button, it will animate the map so you can see it scroll to your location. If you comment out that line and uncomment the line below, when you click the button it will move there immediately.

iPhone MkMapView with home button

I wanted a RadioButton type of effect with three icons. Click one of the other three and it is set to blue and the other two are coloured red. It’s actually very easy once you know the trick. You have to tell iOS 8 that the each icon image is rendered AlwaysOriginal. UIImageRenderingMode is an enum with three values (AlwaysOriginal, AlwaysTemplate and Automatic).

To display the Icon in a colour, set the RenderingMode to AlwaysOriginal then create a UIButton from it and set the TintColor to whatever you want it to be. Image1 etc are declared at the class level as UIImage, btnOne etc is a UIButton and tbar is a UIToolbar.

  tbar = new UIToolbar(new RectangleF(0, 30, 320, 44)); // hard coded values for toolbar size/location
  View.AddSubview(tbar);

  var Image1 =UIImage.FromBundle("images/image1.png");
  Image1.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
  btnOne = new UIBarButtonItem { Image = Image1, Title = "First Button", TintColor = UIColor.Blue };

// Repeat for button2, 3 etc
//  Add a click handler to each button
   btnOne.Clicked += (s, e) =>
            {
                ClearTints(); // three line method sets all buttons to red
                btnOne.TintColor = UIColor.Blue;
            };
tbar.SetItems(new []{btnOne,btnTwo,btnThree},false );

This shows three icons before and after the second one is selected.

Three icons before and after selection

iOS 8 Deprecated quite a few things- for instance if you did a map search using the Xamarin MapDemo, it uses a UISearchDisplayController but that’s now deprecated and you are meant to start using UISearchController instead.

Knowing which version of iOS your App is running on then becomes important. While I can use the older UISearchDisplayController on iOS 8, I can’t use the newer UISearchController on iOS 7.

Now I’ve been previously using this property to check if the OS is a certain version.

        public bool IsiOS8
        {
            get { return UIDevice.CurrentDevice.CheckSystemVersion(8, 0); }
        }

But I think it’s better to check if a version is >= 7 and for that purposes the MonoTouch.Foundation class provides NSProcessInfo() with it’s OperatingSystemVersion and Major and Minor properties. Note I’ve also changed IsiOS8 from a property to a function.

        public static bool IsiOS8()
{
return (new NSProcessInfo().OperatingSystemVersion.Major >= 8);
}

If you’ve ever wanted a light coloured text status bar, you may have experienced difficulties. If you have the current VS Plugin with current being (in iOS 8.1), Xamarin Studio 5.5.3. My VS plugin 8.4.0.0 and Windows Xamarin 3.7.23.0, then you’ll see you don’t have the choice of picking it in the info.plist editor. The choices are Default, Black Transparent and Black Opaque.

Those last two choices are now deprecated and there should be a Light Content. This changed in iOS 7.0 (see the iOS 7.0 transition guide).

For the fixes, I recommend that you edit info.plist with anything but the VS plugin, at least until they fix it. I use programmers notebook 2 which is excellent.

You need to add the following lines in info.plist:

	<key>UIViewControllerBasedStatusBarAppearance</key>
	<false/>

and in AppDelegate.cs you need to add the following line. I’ve shown it bold and in my code I’m using Tabs so create a Tab Controller (my own class) rather than the usual UIViewController.

            tabController = new TabController();
    UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.LightContent, false);
	    UIApplication.SharedApplication.SetStatusBarHidden (false, false);
            window.RootViewController = tabController;
            window.MakeKeyAndVisible();
            return true;

If you have a launch image you’ll probably want the status bar hidden during launch. If you had previously ticked the hide during application launch checkbox, it adds the following into info.plist.

	<key>UIStatusBarHidden</key>
	<true/>

What this also does with the Light Content fix is keep the status bar hidden so add the second line above (SetStatusBarHidden) as well to unhide it.

To try this fix out, download the code from here :Xamarin Sample for Tab Bars.

Next change the TabBarController so a tab or two is displaying dark colours.

			tab1 = new UIViewController();
			tab1.Title = "Gray";
			tab1.View.BackgroundColor = UIColor.Gray;

and add the one or two lines above to AppDelegate.cs

I’m referring to the button that let you add an unprovisioned iPhone/iPad to the list of devices that you can deploy to. It copied the provisioning profile on to the device and added the device to the list of team members.
I found this out the hard way yesterday when I took my Mac mini to a client’s to add a new iPhone to the test. It was a bit stressful to put it mildly. I had upgraded Xcode to the latest which is 6.0.1.

Xcode Window Devices Menu Item

First the devices are no longer on the main Organizer App window which now shows only Projects and Archives. Click Devices on the Xcode Window menu and you get a form with a list of attached Devices and available Simulators. But No Button! You only got the button when you do this and have an iOS device that hasn’t been provisioned for development yet. Now you have to add the Provisioning Profile through the web interface on Apple’s site. This is surely a retrograde step.

To add a provisioning profile requires the following steps.
1. Log in the Apple Dev Portal and click Certificates, identifiers and Profiles. Click on Devices in the left menu. Note You may have to reset the list before you can add any extra. I assume it’s doing some kind of housekeeping update.

List of provisioned devices

2. You have to copy the UDID from the unprovisioned device and give it a name in the portal. Or you can add up to 100 in one go. 100 is the maximum you can have in your team.

3. Next you have to generate a new provsioning profile. This needs you to have a valid development certificate and all the devices ticked. If you don’t tick the newly added device then you won’t be able to install the provisioning profile on that device.

Generating a Provisioning profile

Back on the Xcode devices list add the provisioning profile to the device. You right click on the Show Provisioning Profiles and click + then browse to where ever the downloaded provisioning profile was. All this instead of one button! Now you can install your App.

A new privacy setting in iOS 8 means that apps using Location services need to have permissions enabled. One way to do this is by adding these extra keys to info.plist. One is for

	NSLocationWhenInUseUsageDescription
        Please allow Location services

        NSLocationAlwaysUsageDescription
        Please allow Location services

Then in settings you’ll see this:

Location Access settings

I noticed this testing an App which relies on GPS. When I ran it on iOS 8, it was not providing location information

My Visual Studio started taking a longish- three to four minutes to load up and then the same when I opened a project. This started after the last Xamarin update. I’ve always found that for best results I have to reboot after an update and then unpair and pair. Sometimes my Mac Mini shows up in the Connection dialog as an IP address and sometime as the name. As the ip is DHCP provided, I figured out using the name was best however..

To cut a long story short, Zone Alarm did not like DNS queries for the Virgin DNS ( 194.168.4.100 and 194.168.8.100 port 53 ) which were resolving the Mac Mini and it was those being blocked that slowed VS down. I figure it must have been a timeout plus maybe some kind of fallback as I could still build projects on the Mac.

So if you ever get that kind of slow down, check your firewall!

I’ve not mastered AutoLayout, but if you want to resize a label, there’s a few of things you need to do. The image below shows a slider used to control a font size.

 

Resizing a label with a slider

Here I’ve omitted the declarations but fontlabel is a UiLabel, Support.FontSize is a float, and fontSlider is a UISlider. This is the code.

            fontlabel = new UILabel()
            {
                Text = @"Font Size",
                Lines = 1,               
                TextColor = Support.uTextColor,
                BackgroundColor = Support.BackColor,
                LineBreakMode = UILineBreakMode.WordWrap,
                Frame = new RectangleF(10, 320, Frame.Width - 20, 30),
                Font = UIFont.FromName("Helvetica", Support.FontSize)
            };
            fontlabel.SizeToFit();
            AddSubview(fontlabel);
            fontslider = new UISlider(new RectangleF(5, 350, Frame.Width - 5, 30))
            {
                MinValue = 11f,
                MaxValue = 30f,
                Value = Support.FontSize
            };
            fontslider.ValueChanged += HandleFontSliderChanged;

        private void HandleFontSliderChanged(object sender, EventArgs e)
        {
            Support.FontSize = fontslider.Value;
            fontlabel.Font = UIFont.FromName("Helvetica", Support.FontSize);
            fontlabel.SizeToFit();
        }

Allow enough room for the label to fit at its largest size and having changed the font size in the Slider event, call SizeToFit() on the label. Otherwise you’ll find that the text is truncated when the label is made larger.