Our products

We are passionate about building niche multi-platform products that provide real utility to our customers.

Anfield
Keep up to date with Liverpool FC news from across the web.
Domain Bites
Domain name industry news and resources.
Pub Reviews
Find the best pubs near you. Share your thoughts and photos.
Mmmm
Capture your taste and share it with the world.

Blog

We like to blog about software. Our stack, engineering problems, open source developments.. you will find it all discussed here.

Twitter's Fabric APIs for Android are a little bit sloppy..

The content of this post relates to version 1.12 of Twitter's Android APIs (which were the latest versions at the time of publishing)

One of the most annoying things that I have encountered as an engineer is those situations whereby you encounter an issue which you are adamant that you have encountered before yet cannot remember how to fix.

I had one of those moments today when utilising Twitters Fabric APIs for Android.

My issue was not a bug, but rather a missing piece of functionality (bad Twitter !).

onActivityResult

It is well known that in an Android application when you call startActivityForResult the result is received in the onActivityResult method of your Activity.

If you call it from a Fragment (fragmentInstance.startActivityForResult), the Activity will pass the call to its onActivityResult method onto the Fragment IF you make sure to call super.onActivityResult within the Activities implementation. This is all handled by the Android framework, and is extremely useful when building Fragment based applications.

Unfortunately Twitter's API does not provide an authorisation endpoint which executes from a Fragment context. If you take a look at the TwitterAuthClient source code you will see that they have a method authorize which takes an Activity context but not one which takes a Fragment context. As such you have to handle passing the onActivityResult call from the Activity to the Fragment yourself.

This is not the end of the world, but it is such an easy thing to implement that it is really bemusing as to why Twitter have not implemented such a method. It would be somewhat OK had they provided concise and clear documentation for utilising their API but sadly all they provide is a very basic overview of how to use their widget-esque offerings (namely TwitterLoginButton). If you want any kind of customised Twitter login experience (who doesn't), then you are on your own.

What is your requestCode?

As if that wasn't bad enough, to be able to implement such functionality in a safe and consistent manner (that is future-proofed from API updates) you need to know the request code which Twitter is using to 'start its Activity for a result'. It just so happens that the request code is 140, but were you not aware of that you'd have to find out somehow so as to discern when to pass calls to onActivityResult onto the Fragment interacting with Twitter's APIs.

I could not find this information in their documentation - once again I had to look in the source. The value is defined in a static property TwitterAuthConfig.DEFAULT_AUTH_REQUEST_CODE. The naming convention of the property suggests that as it is a default there would be some way to change it. There is not.

There is a getter on the TwitterAuthClient class - getRequestCode, but that simply calls a method on TwitterAuthConfig which returns the hard coded value '140'. The getter doesn't even use the constant :)

OK, I am sorry

All things considered, these issues are not particularly significant. My problem is that Twitter is a massive company with a really large engineering team.

They have built Fabric (which on the whole is an amazing product) which allows me to build applications on multiple platforms to interact with Twitter (which is itself an awesome platform). They (I suspect) built this product to make it easy for app developers to integrate with their services so as to grow their own user base and increase their social impact.

Given that, I cannot get my head around the idea that you'd build a complete and feature rich API and then miss out some simple but incredibly useful functionality that contradicts generally recognised patterns for the platform you are targeting. Weird.

Documentation

As I alluded to above, the Twitter API documentation is somewhat lacking. I guess that they want you to use their widgets rather than implementing custom flows.

It is however (in my opinion) completely reasonable to expect developers to want to implement custom flows, and for the same reasons outlined above I do not see why they have not invested the small amount of required time in improved documentation so as to aid developers in integrating their products with Twitter.

So..

Hopefully someone at Twitter will see this and share some insight as to why they have written their Android APIs in this manner.

What are your thoughts? Am I just being unreasonable and ungrateful?

Making an overlay screen in Android

Yesterday I encountered a problem when building the latest version of the MMMM Android app.

That problem was that when uploading a new photo to the site, subject to the user pressing 'Continue' before the upload is complete, I wanted to show the new photo (and all its information) with a 'Currently uploading overlay'.

My initial thought was that simply placing a text view at the bottom stating as much would be a suitable resolution. It was - it looks good. The problem was that the photo screen displays buttons which open the profile of the uploader, the profile of the photos location, and the profile of the applied tags respectively. Whilst in most cases we have this information (after all the user did just choose it..), in some cases we do not.

For example, we do not require the user to login to upload a photo, but we do create a user account for them (behind the scenes) the first time that they upload. As such we do not know who the uploader is for certain until the upload is complete.

It was important to me that the app had a consistent user experience, and as such I don't want clickable buttons which sometimes pop up with ugly and confusing alerts such as 'We cannot go to the uploaders profile because we don't know who you are'. Allowing people to press 'continue' before the upload is complete is purely for the sake of user experience, but we still want the upload to complete..

As such, I opted to extend the overlay such that it covers the whole of the photo activities tab content. The intention being that the user not be able to click or action any control until the upload is complete. That means no adding comments (you can't add a comment if the photo isn't saved in the database), no rating photos, and no profile clicks.

Adding an overlay view

Adding an overlay view was in itself less simple than I had expected.

Having gained some insight from this StackOverflow answer, I ended up with the following:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <LinearLayout
            android:id="@+id/statusLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <View
                android:id="@+id/overlay"
                android:layout_width="wrap_content"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:background="#66000000" />

            <TextView
                android:id="@+id/statusMessage"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#c0000000"
                android:gravity="center_horizontal"
                android:padding="5dp"
                android:text="Uploading"
                android:textColor="@color/tw__solid_white"
                android:visibility="visible" />

        </LinearLayout>
    </FrameLayout>

    <com.mmmm.com.Custom.MMMMFragmentTabHost
        android:id="@android:id/tabhost"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/top_border" />

</LinearLayout>  

This is the view for my tab host which hosts three fragment tabs. Simply setting the overlay visibility property to visible will display a semi transparent overlay over the content of whichever tab is being displayed. Great !

I can still click

One surprising problem hat i encountered at this point was that I could still click buttons that were underneath my overlay but I could not scroll the content (scroll view) below.

Given that I still want the uploader to be able to see the information that we are uploading, continuing to allow scrolling the content underneath would be great BUT under no circumstances do we want any buttons to be clickable. That would defeat the point of the exercise.

Implementation

Having previously built my own Pull to Refresh component, I was well aware (albeit a little rusty) as to how Android works in regards to intercepting touches.

Now.. the reason that the Button elements below receive the clicks is because by default they have the property android:clickable=true. Our overlay does not, and as such it does not intercept and act on the touches. A simple resolution is to add the clickable property to our overlay view. This intercepts clicks, and prevents the buttons from being triggered.

The problem is that this also prevents any touches reaching the ScrollView - we cannot scroll the content underneath.

As such we need to intercept the touches on the overlay view and conditionally pass them to the child ScrollView when needed whilst not passing clicks to the buttons below.

The code that I came up with (based heavily on the discussion here is as follows:

final FrameLayout tabContent = (FrameLayout) view.findViewById(android.R.id.tabcontent);

        View overlay = (View) view.findViewById(R.id.statusLayout);

        overlay.setOnTouchListener(new View.OnTouchListener() {

            private float mDownX;
            private float mDownY;
            private final float SCROLL_THRESHOLD = 10;
            private boolean isOnClick;

            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {

                switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {

                    case MotionEvent.ACTION_DOWN:

                        mDownX = motionEvent.getX();
                        mDownY = motionEvent.getY();
                        isOnClick = true;

                        tabContent.dispatchTouchEvent(motionEvent);

                        break;

                    case MotionEvent.ACTION_CANCEL:
                    case MotionEvent.ACTION_UP:

                        if (isOnClick) {

                            Log.i("LOG", "onClick ");
                            //TODO onClick code

                        } else {

                            tabContent.dispatchTouchEvent(motionEvent);
                        }

                        break;

                    case MotionEvent.ACTION_MOVE:

                        if ((Math.abs(mDownX - motionEvent.getX()) > SCROLL_THRESHOLD || Math.abs(mDownY - motionEvent.getY()) > SCROLL_THRESHOLD)) {

                            isOnClick = false;

                            tabContent.dispatchTouchEvent(motionEvent);
                        }

                        break;

                    default:

                        break;
                }

                return true;
            }
        });

I don't like spoiling the fun, and feel that there is certainly a good learning experience to be had here. As such I have opted not to 'over-comment' the code.

The basic premise is that we discern as to whether the user is clicking or swiping (based on a movement threshold). If the latter, we want to pass it to our tab content to handle (the scroll view will move). If however the user has clicked, we do not want to pass it to the tab content below.

Because an MotionEvent.ACTION_MOVE event requires a MotionEvent.ACTION_DOWN event to have occurred before, and an MotionEvent.ACTION_UP event to occur afterwards, we make sure to pass those down to the tab content at the appropriate times.

Alternatives

Depending on how often you intend to utilise such an overlay, it may well be worth implementing the above listeners in a custom View subclass such that you do not have to implement complex onTouchListeners in every place you want to use it.

Benefits

The reason that this solution works so well for me is because I can control the overlay in the Activity which displays my tab host/content. I do not need to give any consideration to the views of the fragments actually hosted in the tab host. Simply passing the touches to the tab contents FrameLayout (as appropriate) simply passes the ball back to the Android framework in the appropriate place to allow for it to work its magic.

We could have absolutely any tab fragment content below and the specified touch messages would still be passed down to it.

The result. You can scroll the content.

So...

Hopefully that has provided a little further insight should you wish to implement something similar. If you come up with an alternative interesting use case for such an overlay, please do share - I would love to hear what cool functionality people are implementing.

Any questions or comments..? Just let me know !

Ethereum - Is this the next web?

At the end of October there was a rally in the price of Bitcoin. Having not heard much about the infamous cryptocurrency in a number of months, it was all of a sudden back on our radar.

It rose up to a peak of around $500 in early November, and then dropped back down. Over the following month, in typical Bitcoin fashion it has been all over the place.

Given our association with domain names, and given my background in Economics it seems reasonable to suggest that Bitcoin would be of significant interest as a potential investment opportunity. This is a fair assumption, and in fact over the past 6 years Bitcoin has been on my radar on a number of occasions.

Browsing through my historical mail archive i was intrigued as to whether I might have bought some Bitcoin all those years ago (and be sitting on a treasure trove). Unfortunately I did not.

There were a number of Bitcoin related emails - signing up for wallets, downloading mining software, conversing with fellow investors etc. Unfortunately I never pulled the trigger. If I recall correctly it was simply too complex, and not compelling enough as an investment opportunity. Oops.. or was it?

Looking at Bitcoin now, it could be another of those make or break moments. That is to say one could look back in a years time and question as to why they didn't invest in the now $1000 Bitcoin. Then again.. that is merely hindsight. It could drop drastically, and I could be breathing a sigh of relief.

Why are we not investing in Bitcoin

The reason we are not investing in Bitcoin is simple - it (in my opinion) has value based purely on network effects, and blind speculation. There is nothing to back its value, and as such whilst (as has been shown) the potential to make significant sums of money is completely plausible, the potential to lose lots of money is also significant.

I would not bet significant amounts of money on red or black. Nor would I on a coin toss. I see a Bitcoin investment in a similar light.

The other significant reason comes down to scale, and percentage returns. Small numbers seem more friendly. Buying something for $1, and selling it for $2 seems to be a better investment than buying something for $400 and selling it for $800. To take that one step further, I would be more inclined to buy 400 units at $1 per unit and hope that they doubled in value as opposed to buying 1 unit at $400.

Two of my favourite authors (Daniel Kahneman and Dan Ariely) have written extensively about a possible cause of this illogical thought process - Anchoring. The long and the short (and incredibly basic/assumptuous explanation) of it is that whilst Bitcoin sits side by side with Ethereum I am more inclined to invest in the latter simply because of its lower relative cost - it seems like a better deal.

What gives currency value?

Currency - your USD/GBP banknotes and coinage have value because they are demanded. That is to say that people want to have more currency, and as such they are prepared to exchange products and services for said currency.

The problem with Bitcoin is that in the grand scheme no-one is demanding it. With a market cap (at the time of publishing) of around $6 billion, one can see how it comparatively pales into insignificance when one considers that the total amount of currency in circulation (as of 2008) was over $4 trillion USD (see here).

There are a number of people who at this point seem to suggest that Bitcoin has reached that 'too big to fail' point. Whilst Bitcoin is much bigger than any other cryptocurrency at this point in time.. that is a completely ridiculous sentiment in my opinion.

Whilst the concept of Bitcoin is out there, and many people are aware of it.. it is still not well known. I asked a number of people what they knew of Bitcoin, and there were quite a few who did not have a clue what it was. The vast majority had heard of it but had no conceptual grasp of its premise and did not really care for it.

It is my opinion that Bitcoin is speculation - it is not demanded or utilised on a significant scale (as a result of its volatility), and it will not be (in my opinion). It is simply an asset built for speculation in the sense that if you can judge pump and dump cycles well you have the potential to make some good money.

What makes Ethereum different?

Firstly.. Ethereum is different. Whilst it is based off of blockchain technology, it is designed to allow for the programmatic development of smart contracts as opposed to Bitcoin which is simply a currency.

I have tried (and failed) to explain the Ethereum concept to friends, and my mother. It is complex, and at this point it is primitive BUT that is intended and to be expected. The initial release is aimed primarily at tech savvy developers so as to begin developing the Ethereum ecosystem. It is going extremely well.

Take a look at Augur, and Slock.it for example. It may seem far off now, but imagine using people power to predict the future. Imagine a keyless world where you can share anything and everything safely and securely. Imagine a world where you don't need centralised governance ! Imagine not needing a government !!

That last point is particularly pertinent as a friend of mine bought it up relatively recently (without any knowledge of Ethereum and its potential to resolve the issue). Many British people are disillusioned with our form of democracy - politics has in many respects become a question of who is the better liar. Political parties are elected as though there is a 'One party fits all' set of views in relation to everything - this is of course not the case. Ethereum allows for what I term 'micropolitics' whereby you are the government and you can vote transparently on small micro unit policy decisions in a safe, consistent, and fair manner without bureaucracy.

Ethereum allows for anyone and everyone to cast their vote, and those votes to be transparently totalled. Then there are the vast potential cost savings ! For more on this, check out Dominik Schiener's piece Voting on the Ethereum Blockchain.

It is still early days, but I personally think that Ethereum has a lot of potential. Perhaps ten years down the line we will look back at this blog post and think "Wasn't it obvious..". What do you think?

iOS push notifications - the succinct explanation

iOS push notifications are (in my personal opinion) suprisingly difficult to implement properly and debug.

This is especially suprising given that Apple have provided such in depth documentation, and given that there are such an abundance of tutorials on the topic.

The problem is that no single resource has a succinct yet complete explanation. Here it is.

The user needs to be registered for APNS to receive notifications

  • A user can not, and will not ever receive APNS notifications from your app unless they have given explicit permission.

  • In Swift, this can be done with the following code snippet:

let types = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound], categories: nil)  
                UIApplication.sharedApplication().registerUserNotificationSettings(types)
                UIApplication.sharedApplication().registerForRemoteNotifications()
  • Many suggest placing this in your app delegate to request permission on the initial application load. I disagree - you should request permission in response to any explicit user action e.g in response to clicking 'Set up notifications' on your 'Settings' page.

If you want to download data in response to receiving a notification

  • you must add the following property to your plist
<key>UIBackgroundModes</key>  
<array>  
    <string>remote-notification</string>
</array>  
  • You can make your notifications silent by specifying an empty 'sound' key in your payload. Likewise you can display no notification message by setting the 'message' key to an empty value.

Handling all application states

  • If your app is open, and in the foreground you will receive one call to application:didReceiveRemoteNotification:fetchCompletionHandler:.

  • You can check the applicationState property of the passed in application argument. In this case the state will be UIApplicationState.Active

  • To respond to receipt of a call to this delegate method I find it best to dispatch a NSNotification from the default notification center instance. Having already set up an observer in the appropriate view controller, you can pass control over to said controller easily on receipt of the notification.

  • If your app is in the background, you will receive two calls to application:didReceiveRemoteNotification:fetchCompletionHandler:. The first one when the notification is received. The second when the notification is clicked.

  • The first time your application state will be UIApplicationState.Background. The second time it will be UIApplicationState.Inactive

  • Because the application is open (it is just in the background), on receipt of the first call I (again) dispatch a NSNotification that the appropriate controller is listening for. On the second call (when you are bringing the app to the foreground), I do nothing - there is no need to dispatch a second notification.

  • *If your app is closed, you will only receive one call to application:didReceiveRemoteNotification:fetchCompletionHandler: - when the notification is clicked.

  • When closed, there is the additional consideration that your view controller has not been instantiated fully at the point that the application:didReceiveRemoteNotification:fetchCompletionHandler: delegate method is called. As such there is no point dispatching a NSNotification as the observer to listen for it is not set up.

  • In this case, I access and manipulated my view controller directly. You can cast the visibleViewController as you (should) know what your initial view controller is.

let postsController = rootNavController?.visibleViewController as! PostsController  
  • You can then set properties directly on the view controller instance which you can then check for (and act upon) in the viewDidLoad method of the controller.

Tips and tricks

  • If you pass a 'badge' value in the array set as the value for the 'aps' key of your payload, then the system will set the badge on your application icon even if your application is closed.

  • When your application is open or in the background, you can access the current badge value using:

let currentBadgeNumber = UIApplication.sharedApplication().applicationIconBadgeNumber  
  • You can use this knowledge to increment/decrement the badge count within your didReceiveRemoteNotification based on downloaded data. You cannot increment/decrement when the application is closed.

  • When you open the (previously closed) app by clicking on a notification, you can see if the app is being opened due to such a click in the didFinishLaunchingWithOptions method of your AppDelegate with the following code:

let notificationInfo = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey]

if (notificationInfo != nil) {

    //do something
}
  • APNS IDs change ! Even the same version of an application on the same device can have a new APNS ID should you uninstall and then reinstall it. Always check, and keep your server in sync. You might not be receiving notifications because you are sending them to a registration ID that is no longer valid

Register the registered every time

  • That final tip is important enough to warrant its own section. I like to register any previously registered user for APNS in my didFinishLaunchingWithOptions AppDelegate method every time

  • registerForRemoteNotifications is clever. As noted in the documentation:

If your app has previously registered, calling registerForRemoteNotifications results in the operating system passing the device token to the delegate immediately without incurring additional overhead.  
  • That is to say, you may as well check every time the application is loaded if the registration ID has changed. When you sync you registration ID with the server you should also save it locally (perhaps in NSUserDefaults or in your keychain - see SSKeychain). Then in the didRegisterForRemoteNotificationsWithDeviceToken delegate method you can check whether the registration ID has changed.. and if it has, resync it with the server.

The server

  • I am not going to reinvent the wheel. The PHP server code outlined in this tutorial from Ray Wenderlich is good.

  • One thing to note. I found that sometimes, without reason I would get disconnected from the APNS server. I recommend that you dont hide the error output of the following line:

$result = fwrite($this->fp, $msg, strlen($msg));
  • That way you can debug any issues that occur. I didn't find any particular reason for my occasional disconnects, so I simply implemented the appropriate code to establish a new connection should a disconnection occur.

Testing APNS

  • You obviously want to test that your notification setup works correctly prior to releasing your application.

  • Given that APNS profiles are associated with your application bundle identifier I have found that is significantly easier to have distinct bundle identifiers for your development and production applications. This has the added benefit that you can have a development version, and production version of your app on your device side by side. Likewise you can utilise different app icons for each. I recommend that you follow this guide from the team at Circle to get things set up.

  • You can utilise a single bundle identifier (if you wish), but to provision an application for testing (in a manner that will work with the APNS sandbox server) you have to export the application for 'Ad Hoc' deployment from your 'Organizer' and manually put it on your device (through iTunes).

  • Assuming you have gone for the former (better) option, you can simply setup a local server instance to send notifications to the APNS sandbox. Easy.

  • If you are not receiving notifications, my first recommendation as regards debugging is to always make sure you are connecting to the correct APNS server (sandbox vs production), and to make sure that you are using the correct APNS registration ID. Debug and production keys are different.

Conclusion

Having spent a long time looking into the intricacies of APNS it now seems incredibly simple. That said, there are a number of moving parts, and the smallest oversight can cause your notification system to not work at all.

Hopefully the above provides a succinct explanation of those intricacies such that you can implement APNS within your applications without issue.

Let me know how you get on, and if you have any questions/require further clarification.. let me know.