I’ve spent an entire day reading Apple Docs, scouring the web looking at Objective-C code and C# regarding mapping with a view to implementing it in my App. I’m talking about iOS 6 and 7 and in particular Apple Maps.

If you want to use Google Maps be aware that you cannot implement Turn by Turn according to their Google Maps T & C. You must not use the Service or Content with any products, systems, or applications for or in connection with any of the following: “(i) real time navigation or route guidance, including but not limited to turn-by-turn route guidance that is synchronized to the position of a user’s sensor-enabled device.“.

So it’s Apple Maps and MapKit which is jolly good. Now Apple have a lovely Maps app and you can invoke it from your App but that pushes your App into the background. There’s no way to use the excellent Apple Maps Turn By Turn within your App.

using MonoTouch.MapKit;
using MonoTouch.CoreLocation;
...
GeoCoder.GeocodeAddress("224 Richmond Road, Leytonstone,E11 4DA", ( placemarks, error) =>
    {
        try
        {
            var coordinate = placemarks[0].Location.Coordinate;
            var placeMark = new MKPlacemark(coordinate,null);
            var mapItem = new MKMapItem(placeMark);

            mapItem.Name = "Where we are going to.";
            mapItem.PhoneNumber = "0203 555 9999";  // Not a real number (I hope!)

            var launchOptions = new MKLaunchOptions();
            launchOptions.DirectionsMode = MKDirectionsMode.Driving;
            launchOptions.MapType=MKMapType.Standard;
            launchOptions.ShowTraffic = false;

            mapItem.OpenInMaps(launchOptions);
        }
        catch (Exception ex)
        {
            var erroralert = new UIAlertView("Location could not be found", "", null, "Ok", null);
            erroralert.Show();
        }                        
    });

That converts the old address (I once lived there – 12 years ago) to coordinates that are passed, along with the Name and Phonenumber to the Apple iPhone Maps App. Here’s what that code produces (dumped from my iPhone).

directions

The Other Way

This involves creating a MapView etc and then asking Apple for directions between points a and b. Rather than explain further I point you to Blake Davidson who has done that (in C#).

I added Default.png and the other variations for iPhone 5, retina display fils and they appeared in the Resources folder. These are for loading screens and are built in as part of the bundle after you add them.

However in doing some work on rolling my own Splash screen so it can have text added, I decided to remove them.

In Xamarin Studio (on Mac) you can unset them, but compiling gave 2 errors about missing files. Looking in the info.plist on the source tab revealed that two strings were still there so I manually removed those. I did a clean then a Build and still got the errors. I did a clean and a Rebuild and still got the same errors. Finally I closed Xamarin Studio down, then reopened it and it built fine. Just a minor irritation.

My App talks to a server over TCP/IP using a well defined packet protocol but I’d been experiencing difficulties of the “packets seem the wrong length” type. I got the server author to debug a conversation.

Now the server sends extra bytes in the middle of messages depending upon the server version of the Client App talking to it. I found this out early on. Anything under version 43 and it omitted two bytes in the middle of the packet.

My App was set to version 200. Androids start at 100, Windows Phone (the first App was created for it) start at 0. The version number is sent as a five char string with leading 0’s so my App sends 00200. It turned out that the part of the server that verified and classified messages only checked the last two digits. D’oh!

Hence my server seemed to be version 0. Until the bug is fixed, my App is now version 00260.

I can’t do it but if you are available (immediately I guess) near Bedford for a contract with Capita, contact Kate Winton at Capital Internal Resourcing. She is looking to recruit a C# Developer for a mobile app development project with Capita Children’s Service. This is initially a 3 month contract based in Bedford.

The key skills we’re looking are C#, Objective-C, XAML or Xamarin and iOS development.

Her contact details are:

Kate Winton, Contracts Delivery Consultant

Internal Resourcing, 1st Floor Kings Chase, 107 King Street, Maidenhead, Berkshire SL6 1DP
Tel. +44 (0)1628 408185 | Fax. +44 (0)870 8555 643 | Email: katherine.winton@capita.co.uk

picture of emailed-log in gmailThis is a screenshot of a log viewed in Gmail.

This is a follow up to the post So I rolled my own logger. In that post I provided a simple logger class.

In this post I use http to send all the logs rolled up into one text file to a php script which emails the file to me. Remember, iOS does not allow you to send email programmatically.

        // helper function to retirn path
        public static string GetLocalFilesPath()
        {
            var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            return Path.Combine(documents, "..", "Library", "Caches");      
        }

    public static void EmailLogs()
    {            
        const string url = "http://example.com/email.php";
        var sb= new StringBuilder();
       
        try
        {
            Support.log.Pause();
            var dirInfo = new DirectoryInfo(Support.GetLocalFilesPath());
            var lstFiles = dirInfo.GetFiles("*.log");
            foreach (var info in lstFiles)
            {
                sb.AppendLine("-------------------------");
                var fInfo = info; // avoids closure bug
                sb.AppendLine(fInfo.Name);
                using (var sr = new StreamReader(fInfo.FullName))
                {
                    sb.Append(sr.ReadToEnd());
                }
            }
            var msg = WebUtility.UrlEncode(sb.ToString());
            var fullMsg = "z=xyz23&mid="+UNIT.MobileID+@"&alphasid="+UNIT.SystemID+@"&lui="+msg;
            Task.Factory.StartNew(() => HttpPost(url, fullMsg), TaskCreationOptions.LongRunning);
           
            foreach (var info in lstFiles)
            {
                info.Delete();
            }            
        }
        catch (Exception)
        {

        }
        finally
        {
            
        }            
        return; 
    }

Support is a class that includes a static instance of the logger class. This is a wrapper round a StreamWriter so the pause method closes the StreamWriter otherwise we’d be tring to read from a file that[‘s open in the StreamWriter. After the logs have been sent off the logger is restarted.

This rolls up all the logs it finds into one file using StringBuilder to append the file name and then each line in that log then url encodes it and calls the function httppost below which I found on Microsoft’s site

Note that for security I add in a few parameters. (MobileId and SystemID are static properties from another unit; I’ve changed that to UNIT as my unit name would be meaningless.) Once again I use fire and forget for calling httppost. Ie run it in another Task using the TPL. I’m deliberately not checking any error messages.

    public static string HttpPost(string url, string parameters)
    {
        try
        {
            //Create a WebRequest
            var req = (HttpWebRequest)WebRequest.Create(url);

            //Set the content type and method
            req.ContentType = "application/x-www-form-urlencoded";
            req.Method = "POST";

            //Get the total size of the post parameters and set the content length
            var bytes = System.Text.Encoding.UTF8.GetBytes(parameters);
            req.ContentLength = bytes.Length;

            //Write the data to the request stream
            Stream os = req.GetRequestStream();
            os.Write(bytes, 0, bytes.Length);
            os.Close();

            //Get the response
            WebResponse resp = req.GetResponse();
            if (resp == null) return null;

            //Get the response stream and read the response
            var sr = new StreamReader(resp.GetResponseStream());
            string result = sr.ReadToEnd().Trim();

            //Close the streams
            sr.Close();
            resp.Close();

            return result;
        }
        catch (Exception)
        {
            //Epic fail...
            return null;
        }
        finally
        {
            Support.log = new Logger();
        }
    }

Finally I have a small PHP script setup on a domain hosted on a shared server. Note the use of security parameters to stop spammers using this script to bombard you with spam. The parameters below should match the parameters in this line from above:

var fullMsg = "zvf=xyz23&mid="+UNIT.MobileID+@"&alphasid="+UNIT.SystemID+@"&lui="+msg;

This is the PHP script below, after validating that it’s a genuine request, it takes the three parameters, appends the log file to a local text file then emails it to the specified email address.

I have the error messages commented out as they’re only there for debugging purposes.

There are plenty of logging systems about for .NET. This site although it’s an advert for a .NET logging system has links and comparisons with many.  But sometimes all you need is a very simple logger, something as simple as appending a string to a text file. So here’s a 64 line logger that creates a dailyfile – for today it’s 20131004.log.

using System;
using System.IO;
using System.Threading.Tasks;

namespace TMRTaxi
{
    class Logger : IDisposable
    {
        public string FileName { get; set; }
        private StreamWriter sw;

        public Logger()
        {
            var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            var cache = Path.Combine(documents, "..", "Library", "Caches");
            var logfile = Path.Combine(cache, @"log" + DateTime.Now.ToString("yyyymmdd") + ".log");
            FileName = logfile;
            var str = "Logging Startedn";

            sw = new StreamWriter(FileName, true);
            Log(str);

        }

        public void Pause()
        {
            if (sw != null)
            {
                sw.Flush();
                sw.Close();
                sw = null;
            }            
        }

        public void Log(string msg,string comment="")
        {
            if (sw == null)
                return;
            msg = DateTime.Now.ToString("T") + " : "+msg+(comment != ""?" ["+comment+"]":"");
            Task.Factory.StartNew(()=> sw.WriteLine(msg), TaskCreationOptions.LongRunning);           
        }

        public void Dispose(Boolean disposing)
        {
            if (sw != null)
            {
                sw.Close();
                sw = null;
            }    
        }

        public void Dispose()
        {
            Dispose(true); //i am calling you from Dispose, it's safe
            GC.SuppressFinalize(this); //Hey, GC: don't bother calling finalize later
        }

        ~Logger()
        {
            Dispose(false); //i am *not* calling you from Dispose, it's *not* safe
        }
    }
}

It could probably do with a bit of extra error checking. A try catch round the sw = new StreamWriter(FileName, true); line for instance.

These lines:

var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            var cache = Path.Combine(documents, "..", "Library", "Caches");
            var logfile = Path.Combine(cache, @"log" + DateTime.Now.ToString("yyyymmdd") + ".log");

create the log file in the caches folder.

This line Task.Factory.StartNew(()=> sw.WriteLine(msg), TaskCreationOptions.LongRunning); in Log() does a fire and forget. It runs it using the TPL (Task Parallel library). It seems to work fine.

Just creature a logger with

log = new Logger();
log.Log("App starting up");

Plus there’s an optional comment on the Log method.

Of course it would be nice if you can email the logs to yourself but programmatically that’s a no no. “Apfel verbietet es” as my German teacher might have said. (“Apple forbids it.”).

The workaround is to build a large text file from all the available log files (and remove them afterwards) then post it to a php script on a website and it emails it. I’ll post the C# code for that in a day or two.

Here’s proof- well it works in the simulator anyway!

ios-simulator