Saturday, March 2, 2013

Connecting any interstitial provider with Admob mediation

Admob mediation provides a way to code your Android app to include banner or interstitial ads just the once but to change the networks supplying those ads on the fly.

I'm going to show you just how easy it is easy to write an adapter that can receive interstitial requests from Admob mediation and serve up interstitial impressions from an ad network.

We need to implement CustomEventInterstitial which performs all the work.

  • requestInterstitialAd() retrieves an ad
  • showInterstitial() displays that ad
  • destroy() performs any cleanup

One thing to remember when retrieving your ad is that you need to notify the mediation layer about whether retrieval was successful or not. So you attach a listener to the ad and when the listener fires, relay that event back to the mediation layer via the mediation listener. Also, if for any reason your network has no ability to retrieve an ad (eg wrong SDK version) then you should report the failure back to the mediation layer immediately so that it can ask the next ad network in the queue for an impression.

Here's the source for requestIntersitialAd()


    
Pretty simple! And to display the ad is even easier.



There's no really much to cleanup here, so that's all the coding.

Make sure to:

  1. Include the libraries for your target network when building your app 
  2. Add Proguard config so leave you mediation adapter intact as the Admob mediation layer will be looking up it via reflection. 
  3. Create a CustomEvent in you Admob mediation config that points to your adapter and passes in the network id for your app.

So now you can serve up ads from any ad network all via Admob mediation. Full source code for the above along with several other mediation adapter and an example app can be found at https://github.com/william-ferguson-au/Admob-CustomEvents

Enjoy

Thursday, January 24, 2013

Simple Google-OAuth2 from a Java client

OAuth is a powerful way to ensure that clients have access to appropriate resources, and the Google OAuth libs do a lot of the heavy lifting for you. But while the doco is pretty good I found it lacking when looking for the most appropriate way to authorize for a simple Java (non-web) application and that's probably to do with the rate at which this area is moving.

It turns out that there are excellent classes in the Google libraries to make OAuth absolutely trivial, in fact it's really only 3 lines:
  1. Construct your AuthorizationCodeFlow
  2. Construct your AuthorizationCodeInstalledApp
  3. Ask the InstalledApp to authorize the client
Here's the full code listing:


Now to make this happen you're going to need to include the relevant Google libs. You can find lots of good info about the libs here google-api-java-client, google-oauth-java-client and google-http-java-client.

The libs necessary for the above are:

Wednesday, July 27, 2011

Tracking user behaviour in an Android app

If your app asks the the INTERNET permission then I recommend that you embed an analytics library into your app right from the start. This will let you get near real time information about who is using your app and how they are using your app.

Adding an analytics library is easy. I use Flurry and at it's simplest you just add the following to each of your Activities:

    @Override
    public void onStart() {
        super.onStart();
        FlurryAgent.onStartSession(this, FLURRY_KEY_FOR_THIS_APP);
    }

    @Override
    protected void onStop() {
        super.onStop();
        FlurryAgent.onEndSession(this);
    }
This will give you all kinds of information about your users. Such as how many times is your app used per day and how much time do user's spend on it. And also in what order are different activities invoked and how much time ares user's spending on each Activity.

Subsequently you can start getting finer grained information by reporting on specified events, such as how times was a new game started and hence on average how many games are played in a single session by a user. This is a simple as adding the following as required.

FlurryAgent.onEvent("gameStarted");

You can even provide a Map of arbitrary parameters to be associated with the event.

final Map<String, String> params = new HashMap<String, String>();
params.put("score", getScore(jumble));
params.put("percentFound", getPercentFound(jumble));
params.put("wordsPerMinute", getWordsPerMinute(jumble));
FlurryAgent.onEvent("gameOver", params);

The event data has let me get a good understanding of how people are playing the game. And helped me tailor my development efforts so that I'm spending time improving areas that are of interest and relevance to my users. Don't get me wrong, direct feedback from user's is gold, but it's rare and it's the voice of a highly motivated individual, it may not reflect the vast majority, that's where the statistics provided by an analytic engine comes to the fore.

Overall the data from Flurry (and I expect any analytic engine) is more than 10 times as much information as is available via the Android Market. I just wish I had it embedded right from the beginning, because it's not entirely clear how many user's are still running old versions for which I have no info.

Tuesday, June 7, 2011

Best 2 design decisions I made for my Android app

I published my first app for the Android ecosystem a bit over a month ago. It's a word puzzle game called Jumblee. There are 2 design decision that I made early on that have paid tremendous dividends and I believe are worthy of consideration for all Android apps.

The first was to include ACRA to capture any app failures no matter what Android version, and to post details of the failure including the stacktrace to a GoogleDoc hosted spreadsheet. You can configure ACRA to report silently or to present a dialog to the user and to capture a variety of information including a user comment. I chose a simple Toast notification and posting of the standard set of fields. I also configured the target spreadsheet so that I receive an email the moment it is modified.

Having ACRA embedded meant that I was aware the instant one of my users found the first bug (and believe me, no matter what testing regime you put in place, Android's heterogeneous hardware and OS environment will cause you to miss something). Before 99% of my users had come across the issue I already had a solution and a new version of my app ready for distribution.

Which leads me to the second decision that has paid back its effort ten fold. Its no use having a new version of your app that fixes a killer bug if no one knows the new version exists. So I built in a component that on startup hits my server to find out the latest version of Jumblee (you could probably have it ping the Market instead using the unofficial market-api). If a more recent version is available it displays a dialog letting the user know and asking if they'd like to download the new version now.

This has meant that my user's have kept rolling forward with new versions quite quickly and I'm not swamped with reports of bugs that have long since been fixed.

I know that the Android Market periodically reminds users about new versions of apps, but the timing of those notifications isn't clear to me, and when I'm confronted with a plethora of updates at once (especially when out of wireless coverage) I sometimes clear and ignore the lot. I'm more likely to accept a single update that is relevant to me right now and I think that is the same for my users.

Well, without these 2, I would have been in a world of pain trying to support my app, and wouldn't have as good a market rating as I do. Its not much of an investment for a heap of gain, so I'd heartily recommend you consider using both techniques.

Bon apetit.

Wednesday, May 18, 2011

AsyncTasks where you control the thread resource

In Android the AsyncTask class is designed to perform some long running task such as DB or net access in a background thread with pre and post execute tasks run on a UI thread, to update your user interface.

In theory its great, in practice it can be a trap.

The problem is that up until Honeycomb AsyncTask only has a single execute method that took no params and that the resource on which the task would execute is shared by all other AsyncTask instances. Worse still the threading resource depends on the version of Android. In Donut (1.5 and now again in the no arg execute method Honeycomb) a single thread is shared amongst all AsyncTask instances. From Eclair to Gingerbread an exhaustible thread pool provides the processing.

This means that if your code uses an AsyncTask it can be blocked by code in another AsyncTask task that might be running unbeknownst to you in a library. This was what was happening to me.

I commonly present a managed dialog before starting a long running task that requires the user to wait until completion and remove it after the task has completed. And I use to do so using AsyncTask. So I started to wonder why sometimes my wait dialogs were taking a REALLY long time to be dismissed. It turns out that a library I use was using AsnycTask (legitimately) to perform net access and update the UI in the post-execute. The problem was that if several of these tasks were started they quickly (or immediately in 1.5) exhausted the AsyncTask processing resource and my dialogs took s long time to go away.

The solution is to create an AsyncTask in which I gain more control of the processing resource available. Which is what has occured in Honeycomb where AsyncTask has gained a new execute method that takes an Executor. But my soluiton needs to work for any version of Android.

So here's my SimpleAsyncTask. It provides 2 execute methods. One takes an Executor and uses that to provide processing resources. The other constructs and starts a new Thread to execute the task.
/**
 * A simple representation of an asynchronous task that has pre and post executions that touch the UI.
 * <p>
 *     It is similar to {@link android.os.AsyncTask} except that it defines its own TaskExecutor
 *     instead of sharing one TaskExecutor between all AsyncTasks.
 * </p>
 * <p>
 *     That means that I can control the task queue and the threads executing the tasks.
 * </p>
 * User: William
 * Date: 16/05/11
 * Time: 7:46 PM
 */
public class SimpleAsyncTask {

    private final Handler handler;

    public SimpleAsyncTask() {
        this.handler = new Handler(Looper.getMainLooper());
    }

    /**
     * Executes this SimpleAsyncTask on its own Thread.
     */
    public void execute() {
        onPreExecute();
        final Runnable runnable = getRunnableToExecute();
        new Thread(runnable).start();
    }

    /**
     * Executes this SimpleAsyncTask using the supplied Executor.
     *
     * @param executor  Executor with which to execute this Task.
     */
    public void execute(Executor executor) {
        onPreExecute();
        final Runnable runnable = getRunnableToExecute();
        executor.execute(runnable);
    }

    /**
     * @return Runnable that executes the pre and post block on the MainLooper UI Thread and the background task in another thread.
     */
    private Runnable getRunnableToExecute() {
        return new Runnable() {

            @Override
            public void run() {
                doInBackground();

                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        onPostExecute();
                    }
                });
            }
        };
    }

    protected void onPreExecute() {
    }

    protected void doInBackground() {
    }

    protected void onPostExecute() {
    }
}
Note that it doesn't cater for generic arguments or passing or arguments from the doInBackground to the onPostExecute methods, IMHO that was over engineered. It is simpler to embed them as attributes in your Task subclass.

It also doesn't expose completion states, but if you need this capability it is trivial to add.

And finally  it doesn't cater for cancellation, but again this is trivial to add, and most of the work will be done in your override of doInBackground method in any case.


 Feel free to use it in any way you can.