Recent Posts

Change Application Name per Release Type with Gradle

Posted on 09 Sep 2014

This is a handy techinique when used in conjuction with the previous week’s tip with separate builds per release type.

To override the application name (and any other resource really), create a new folder under app/src that matches your release name. In this case we’ll be overriding the debug release, so app/src/debug.

Once you have that simply create the same folder structure that is inside app/src/main for overrides. For overriding strings we’ll create app/src/debug/res/values.

Inside the new values folder create strings.xml and add the new app_name value.

app/src/debug/res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

  <string name="app_name">MyApp Debug</string>

</resources>

Now when you install the new debug only application it will have a new name to distinguish between the various release types!

Using gradle to generate a separate development APK

Posted on 02 Sep 2014

Being able to have the same application installed for both development and the release version is very handy. It lets you always have a stable version of the app installed.

app/build.gradle
android {
  // ...

  buildTypes {
    debug {
      // ...
      applicationIdSuffix ".dev"
    }
  }

  // ...

Local SQS development with Redis

Posted on 25 Aug 2014

For SmartChat we used SQS. We used this as a way of sending messages for background workers instead of Sidekiq or Resque. This worked well, but for local development having to use AWS resources wasn’t ideal. We set about creating a way of using Redis instead.

The SQS interface that we used was very simple. It has two methods that were used, #send_messsage and #poll. With this we can make a redis version.

redis_queue.rb
require 'redis'

RedisMessage = Struct.new(:body)

class RedisQueue
  def initialize(redis)
    @redis = redis
  end

  def poll(&block)
    loop do
      queue, message = @redis.brpop("smartchat-queue")
      # queue could be nil if a timeout happened
      if queue
        block.call(RedisMessage.new(message))
      end
    end
  end

  def send_message(message_json)
    @redis.lpush("smartchat-queue", message_json)
  end
end

To use this, we have a AppContainer switch to it for development purposes and use it normally.

config/initializers/app_container.rb
#...
let(:queue) do
  if Rails.env.development? || Rails.env.all?
    require 'redis_queue'
    RedisQueue.new(redis)
  else
    AWS::SQS.new.queues.named(sqs_queue_name)
  end
end
#...
libexec/smartchat-daemon.rb
AppContainer.queue.poll do |msg|
  body = JSON.parse(msg.body)

  # do work
end

Using Gradle to change your API's endpoint per build

Posted on 11 Aug 2014

Forgetting to change your Android application’s API endpoint when publishing to the Play Store is something I did at least three times when building SmartChat. They were all caught quickly and it was only an alpha app, so it wasn’t ever a big issue. However, this is something I would like to avoid.

I searched a bit and found that you could set BuildConfig variables per release type. This lets you never forget to change it again.

MyProject/build.gradle
android {
  buildTypes {
    debug {
      buildConfigField "String", "API_URL", "\"http://192.168.1.2:5000/\""
    }

    release {
      buildConfigField "String", "API_URL", "\"http://example.com/\""
    }
  }
}

With this setup you can access your API endpoint via BuildConfig.API_URL. This will be set at build time and you won’t accidentally forget to change it back when building for the Play Store.

I also found being able to set it different during development was handy so I ended up with this method in my API client.

public String getRootURL() {
  if (BuildConfig.DEBUG) {
    // Change me to whatever you want, this will only matter in development
    return BuildConfig.API_URL;
  }
  return BuildConfig.API_URL;
}

Deploying on multiple EC2 servers with Capistrano

Posted on 04 Aug 2014

For SmartChat we were deploying on EC2. There were three types of serveers to deploy and I used EC2 tags and capistrano to deploy to each server correctly without having to hardcode any of the servers.

Here is my EC2 console with a custom Type key.

EC2 Console with tags

In the deploy script for production we can now use the AWS SDK to pull your instances down and deploy to them correctly.

Dotenv is used because AWS keys are stored in .env and capistrano won’t load that normally.

config/deploy/production.md
require 'aws-sdk'
require 'dotenv'
Dotenv.load

set :rails_env, "production"

primary = true

ec2 = AWS::EC2.new
ec2.instances.tagged("Type").tagged_values("web").each do |instance|
  next unless instance.status == :running

  # We only want one application server migrating the database
  server instance.public_dns_name, :web, :app, :db, :primary => primary

  primary = false
end

ec2.instances.tagged("Type").tagged_values("worker").each do |instance|
  next unless instance.status == :running
  server instance.public_dns_name, :worker, :app
end

ec2.instances.tagged("Type").tagged_values("scheduler").each do |instance|
  next unless instance.status == :running
  server instance.public_dns_name, :scheduler, :app
end
Creative Commons License
This site's content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License unless otherwise specified. Code on this site is licensed under the MIT License unless otherwise specified.