Showing posts with label iphone. Show all posts
Showing posts with label iphone. Show all posts

Sunday, 6 April 2014

Review of the Nokia Lumia 1320 - Focus on Apps

This review focuses on my the apps available for the Nokia Lumia 1320 Windows Phone. 

Preamble

As part of a competition run by Gizmodo UK, I have won 3 new smartphones. In exchange for keeping the phones I have agreed to write some unbiased reviews.

A version of this review can be read in an article on Gizmodo UK. This blog post is the full, unedited version.

"Nokia appears to be doing as much as Microsoft, if not more, in making Windows Phone an attractive and viable smartphone option"

Thursday, 6 September 2012

Programmatically get User-Agent String - Android and iOS

This post details how to obtain a device's default User-Agent string for Android and iOS development.

Getting programmatic access to a device's User-Agent string isn't always easy; in fact, it seems outright difficult in a lot of cases. This post will detail how you should obtain such information when developing for Android and iOS. Note, the information on the Android section requires Android 2.1 and up (more details below).

What is a User-Agent string?

User-Agent strings provide details about the device that is making a request to a server. Basically, it is a way of helping the server identify what kind of device is asking for data.

Here is an example, of an iPhone running iOS 6 (Beta):
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.2

What does 'default User-Agent' really mean?

That's a good question. By my definition, the default User-Agent basically refers to the User-Agent string that the device's default browser would use when requesting websites. Each browser of course, will likely send a modified User-Agent string.

Why do I need to care?

User-Agent strings are often an essential piece of information when submitting data to a server; the server might require it to cater device-specific optimised data, the server might just want to log it, or it might well just refuse to release data to a request that hasn't provided it.

In the simplest of examples, when using a browser to access a website, the server might look at your User-Agent string and decide whether to serve you the "desktop" page, or the "mobile" page, based on what data is provided in your User-Agent string.

Providing a hardcoded User-Agent string in your app might seem tempting, but this can really result in a bad user experience for users, depending on how/if the server uses that information. As every good developer knows; it is all about the user experience! Thankfully, you don't have to bend over backwards to find the User-Agent string.

Android

Since Android 2.1, a system property has been included which contains the default User-Agent string. This is really great as it allows quick retrieval of the UA string without the overhead of creating a Web View, simply to extract the string.

String userAgent = System.getProperty("http.agent");

iOS

In order to obtain the User-Agent on iOS, you need to instantiate a UIWebView, and execute a javascript command to obtain the UA string.

UIWebView *webView = [[UIWebView alloc]initWithFrame:CGRectZero]; 
NSString *uaString = [webView stringByEvaluatingJavaScriptFromString:"@navigator.userAgent"];


A good tip here is to execute the above once, and assign it to a variable - the User-Agent string is not going to change during the execution of your app, and it is more efficient than performing an instantiation of a UIWebView often, just to get the same string.

Tuesday, 21 August 2012

iOS 6 User Agent String

Today, I needed to have a look at the User Agent string from a device running iOS 6. A device I have is running iOS 6 beta 4, provides the following header.

User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25 

As this is a beta, there is the chance it will change, and of course, it might even vary from iPhone to iPhone. However, for anyone needing an example User Agent string, there you go.

If you are looking for gaining access to a device's User-Agent string programmatically, then you should look no further than here, http://cdrussell.blogspot.co.uk/2012/09/programmatically-get-user-agent-string.html.

Tuesday, 31 July 2012

Could Not Instantiate Class Named 'NSLayoutConstraint'

Back into iPhone development again, I found myself briefly scratching my head at an app crashing when testing on one of my real devices, but not another. The console shows a stack trace with the pertinent complaint being


*** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: 'Could not instantiate class named NSLayoutConstraint'*** 

Well that's no good now is it ? I found that it runs just fine on my iPhone running iOS 6 beta 3, but crashes out with the above error when running on my iPod 5.1. It turns out that the new Xcode has introduced some new functionality into the Interface Builder, some of which is enabled by default when creating new XIBs.

The offending item is this case, is the use of "Autolayout" of interfaces. It seems that when using Xcode to create new interfaces, Autolayout is checked by default, even though it is a feature available for iOS 6 onwards. My project targets iOS 4, so I was a bit surprised to see it assume such a breaking setting, but maybe that is just because the Xcode version I am using is also still in beta (Version 4.5 4g125j).

The fix is quite simple, Select the XIB which is failing to load, and from the panes down the right, find the one entitled "Interface Builder Document". Under here, are settings for deployment versions (which represents the minimum version you want to support), which can be changed to match your expectations.





Selecting the correct version will result in the build failing, quoting a build error such that:

Auto Layout on iOS Versions prior to 6.0

Underneath this setting, is a checkbox entitled "Use Autolayout" which should be unchecked, as per the build error. Rinse and repeat for any other XIBs you have created using Xcode 4.5.

Thursday, 12 April 2012

iOS - Integrating KIF Tests with Jenkins CI


Below is the script I use in Jenkins to kick off my automated GUI tests, which are performed using KIF which was developed by Square. KIF serves as an excellent start for running and automating GUI testing. I had to make a small change to KIF to support entering text into text fields which weren't empty; KIF didn't seem to handle this so I made a fix in a fork, located at my KIF.


One of the problems I had initially was that whilst the build would be marked as successful or a failure correctly, there was no feedback on which of the GUI tests failed. My script below solves this problem by outputting the feedback from KIF if and only if the GUI tests fail; if they are successful there is no need to see them in my opinion.


Your script would need to be adapted to contain the correct details for your project/workspace/scheme/target of course, but hopefully this will serve as a good guide.


Waxsim is the required bridging application needed to support integration between KIF and Jenkins. Waxsim has been installed on the server, running under /Applications/waxsim - if you have it installed elsewhere then update the reference accordingly.


#!/bin/sh
#kill simulator if running
killall -s "iPhone Simulator" &> /dev/null
if [ $? -eq 0 ]; then
    killall -KILL -m "iPhone Simulator"
fi


echo "About to build GUI tests scheme"


xcodebuild -scheme "GUITests" -workspace "xxx.xcworkspace" -configuration Debug -sdk "/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/" build CONFIGURATION_BUILD_DIR="/var/hudson/workspace/$JOB_NAME/build" 


echo "About to run waxsim - a long delay here might suggest something is obstructing the view of the simulator on build slave"


/Applications/waxsim "/var/hudson/workspace/$JOB_NAME/build/GUITests.app" > /tmp/KIF-$$.out 2>&1


# WaxSim hides the return value from the app, so to determine success we search for a "no failures" line


echo "Testing finished"


# count the number of times "TESTING FINISHED: 0 failures" is found - 0 means that there was a failure
success=`exec grep -c "TESTING FINISHED: 0 failures" /tmp/KIF-$$.out`


# if there was a failure, show what waxsim was hiding and crucially return with a non-zero exit code
if [ "$success" = '0' ]
then 
    cat /tmp/KIF-$$.out
    echo "==========================================="
    echo "GUI Tests failed"
    echo "==========================================="
    exit 1
else
    echo "==========================================="
    echo "GUI Tests passed"
    echo "==========================================="
fi

Tuesday, 10 April 2012

Script to Kill iPhone Simulator if Running

Instructions to end the iPhone Simulator process if it is running.

As part of a CI setup, it is typical to have multiple iOS build jobs running on an individual build slave. As you can only have a single instance of the iPhone Simulator, you might find some of your jobs fail because another job has started the simulator, and you can't get access to it.

What seems like a sensible approach here, is to kill the simulator if it is already running, meaning your build job is guaranteed to start from a known state. If you attempt to close the simulator when it isn't running, however, you will end up with an error, along the lines of "No matching processes belonging to you were found". That's why you need to check if the process is running first, before attempting to close it.

The following script checks if the simulator is running, and if it is, ends the process. You can do this at the start of each build job.


#!/bin/sh
#kill simulator if running
killall -s "iPhone Simulator" &> /dev/null
if [ $? -eq 0 ]; then
    killall -m -KILL "iPhone Simulator"
fi




And in case you were wondering; this works for the iPad simulator too. The process is the same so the script above works unedited.


If you have any problems getting this going, drop me a comment below.

Thursday, 27 October 2011

iPhone Development - Turn On Automatic Reference Counting (ARC) on a Single File in a Project


Off the back of my other post, Turn Off ARC, which instructs you how to configure Xcode to disable ARC for individual files, this post is the polar opposite; how to enable ARC for individual files.

To enable ARC for a single class, you should go to the "Project Navigator", click on your project, and then select the "Build Phases" tab. From the "Compile Sources" dropdown, find your class on which you wish to enable ARC. Note, you enable this on the .m implementation files, not the .h header files.

Notice that there are two columns here, "Name" and "Compiler Flags". Double click in the relevant "Compiler Flags" column for your desired class, and the following:

-fobjc-arc

Clean and Rebuild your project to pick up these changes. Note, as far as I know, you cannot apply this to whole directories in one go, and have to apply it one file at a time.

Wednesday, 26 October 2011

iPhone Development - Turn Off Automatic Reference Counting (ARC) on a Single File in a Project

Xcode has introduced ARC from version 4.2 and above (compatible with iOS 4.0 and above) and it is excellent. All new projects you create will have it enabled by default (you can uncheck this during the new project wizard if you so desire) and that is just lovely.

But what if you need to import legacy code, or another party's source code that hasn't been coded with ARC enabled? You need to remove all manual memory management commands such as release, retain, autorelease etc... if you want to enable ARC. So if your legacy or third party code has these in it and you can't or don't want to edit the code, then you'll have to tell Xcode that ARC is disabled for these files.

Thankfully, Xcode allows you to have ARC enabled for the whole project, but disabled on a select number of files.

To disable ARC for a single class, you should go to the "Project Navigator", click on your project, and then select the "Build Phases" tab. From the "Compile Sources" dropdown, find your class on which you wish to disable ARC. Note, you disable this on the .m implementation files, not the .h header files.

Notice that there are two columns here, "Name" and "Compiler Flags". Double click in the relevant "Compiler Flags" column for your desired class, and the following:

-fno-objc-arc


Clean and Rebuild your project to pick up these changes. Note, as far as I know, you cannot apply this to whole directories in one go, and have to apply it one file at a time.


For details on how to enable ARC for individual files, see my other post, Turn On ARC.

Monday, 24 October 2011

Custom HTTP Headers in iPhone UIWebView


If you've done much coding for iPhones, you'll likely have come across the UIWebView class. It is what allows you to use an embeddable web browser component, within your app. It's a useful component that lets you view web pages straight from within your app, using the very capable rendering capabilities granted to the iPhone's full Safari browser.

The problem I faced today, however, was that I needed to customise some of the HTTP headers that are sent to servers, when using the UIWebView component. Turns out that this is possible, although not as straight forward as I first expected. Why might you want to do this? Well you might want to alter the HTTP User Agent string, add some custom headers that your server requires, alter the language supported by the Accept header or you might well just be really curious.

Read the solution after the break.