Friday, 20 March 2015

Using Swift code in Objective-C

I had a right pain getting this to work, once again Apple seem to have created something bafflingly unintuitive. I found these instructions elsewhere and have copied them virtually unmodified:

The file name of the generated header is "ModuleName-Swift.h". The ModuleName here is the Product Module Name, here's how to get to it:

1. Select your project in Project Navigator, then select project name under the word Project, so it’ll show you your project settings.

2. Select Build Settings tab on top, and find the Packaging section (you can type its name in the search bar). Here’s Product Module Name. If its value is the name of your project, then let it be, but you may want to change it if the value is a little bit different from the name of the project. I’d recommend not to use spaces or any other non-alphanumeric characters, here’s why:
If it has spaces or any other non-alphanumeric characters, they’ll become replaced with underscores (_) in the header file name. Also, Apple tells us that “if the name begins with a number, the first number is replaced with an underscore”.

Now build the project. Make sure that you have no build errors at all — Xcode must say “Build succeeded”. If it happened, then Xcode have probably generated the header. It won't appear in your project in Xcode or in its folder. It’s generated into a temporary build directory. Try to import it into the file where you want to use your Swift code by typing

#import "ModuleName-Swift.h"

In which ModuleName is your Product Module Name. You have to type it blindly, there’s no autocompletion here. So type this and build your project again. If you got “Build succeeded” message, then you’re done and Swift code is successfully integrated into Objective-C. It even autocompletes your class names, methods and variables written in Swift.

Tuesday, 17 March 2015

Android action actionDone button not appearing on soft keyboard

So, I have an EditText field, and I wanted the user to be able to dismiss the keyboard with a 'Done' button on the keyboard. So I added the following to my EditText element in the layout xml:
android:imeOptions="actionDone"
But this didn't work. No button on keyboard! Eventually I got it working by adding the following as well:
android:singleLine="true"

Monday, 16 March 2015

Xamarin - async post to REST service

Today I had to make a Xamarin Android app post a user's email address to a server. I created a new REST service using MVC Web API, with a simple single-table code-first Entity Framework database behind it.

At the app end, I assigned an async click event to the submit button like below. This is non-critical functionality and the response from the server was irrelevant here so I didn't need to do anything with it, and nor did I have to re-attempt at a later time in the case of no network availability:
            //OnCreate

            var btnContinue = FindViewById<imagebutton>(Resource.Id.btnContinue);
            _txtEmail = FindViewById<edittext>(Resource.Id.txtEmail);

            btnContinue.Click += async (sender, e) =>
            {
                //TODO validate email input and check not null

                //send email to email REST api
                JsonValue json = await PostEmailAsync("http://myrestservice.net/api/User/", _txtEmail.Text);

                //could do something with response here if necessary

                // Send the user to next screen, or do anything with the UI you need to.
            };


             //PostEmailSync

         private async Task<jsonvalue> PostEmailAsync(string url,string email)
        {  

            var cm = (ConnectivityManager)AppContext.GetSystemService(ConnectivityService);
            var activeNetwork = cm.ActiveNetworkInfo;
            var isConnected = activeNetwork != null && activeNetwork.IsConnected;

            if (isConnected)
            { 
                // Create an HTTP web request using the URL:
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
                request.ContentType = "application/json";
                request.Method = "POST";

                using (var streamWriter = new StreamWriter(request.GetRequestStream()))
                {
                    string json = "{Email:'" + email + "'}";

                    streamWriter.Write(json);
                    streamWriter.Flush();
                    streamWriter.Close();
                }


                // Send the request to the server and wait for the response:
                using (WebResponse response = await request.GetResponseAsync())
                {
                    // Get a stream representation of the HTTP web response:
                    using (Stream stream = response.GetResponseStream())
                    {
                        // Use this stream to build a JSON document object:
                        JsonValue jsonDoc = await Task.Run(() => JsonObject.Load(stream));
                        Console.Out.WriteLine("Response: {0}", jsonDoc.ToString());

                        // Return the JSON document:
                        return jsonDoc;
                    }
                }
           }
   
            return null;
        }