Category Archives: Coding

How to create multiple builds for a single Android project using Gradle

For my Android project, I wanted to create different APKs that can be installed on the same device – specifically a debug version and a release one. There are two ways of doing this – one is using the concept of Build Flavors and the other is using Build Types. Build Types is more fitting in this case as Build Flavors is intended for major code differences such as having a different code base for release a version for the Play Store vs Amazon’s Store. According to this documentation:

One goal of the new build system is to enable creating different versions of the same application.

There are two main use cases:

Different versions of the same application
For instance, a free/demo version vs the “pro” paid application.
Same application packaged differently for multi-apk in Google Play Store.
See http://developer.android.com/google/play/publishing/multiple-apks.html for more information.
A combination of 1. and 2.

The goal was to be able to generate these different APKs from the same project, as opposed to using a single Library Projects and 2+ Application Projects.

This will be helpful when I want to keep the release version with it’s data separate from the constantly changing currently-in-development version.

First step will be to modify the app’s gradle file to include a different suffix for the debug version (noticing also that in the defaultConfig the base application id is specified):


    defaultConfig {
        applicationId "com.sample.package"
        //other config values here
    }
    buildTypes {
        debug {
            //other config values here
            debuggable true
            applicationIdSuffix '.debug'
            versionNameSuffix '-debug'
        }
        release{
            //other config values here
        }
    }

Along with this you can now maintain separate code bases for debug vs release. In the /src directory there’ll be /main and /debug directories which contain the usual sub-directories (java, res, etc.) as well as their own AndroidManifest.xml file. You do not have to actually put anything in the /debug directory but this is where the magic happens. In the case of the manfiest file, the values you define for the debug version will be merged with the main version’s manifest file’s values. This will be useful when addressing some of the gotchas explained in a bit.

Now based on the build variant you select in Android Studio (release or debug) you’ll see either com.sample.package or com.sample.package.debug installed on the Android device being used.

There are some gotchas though. One being if you’re using/declaring a content provider in your manifest file. You’ll get an error complaining about the authority being used for your provider so while in your main manifest file you have this declared:


<provider
   android:name="com.activeandroid.content.ContentProvider"
   android:authorities="com.sample.package.provider"
   android:exported="false"
   android:syncable="false" />

You’ll have to override this by creating a new manifest file in your /debug directory (notice that you don’t have to set the package attribute in the manifest tag):


<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <application>
        <provider
            tools:replace="android:authorities"
            android:name="com.activeandroid.content.ContentProvider"
            android:authorities="com.sample.package.provider.debug"
            android:exported="false"
            android:syncable="false" />
</manifest>

Here we are explicitly declaring that the authority attribute should be replaced when merging with the main manifest file. See the Android tools documentation for reference and more options.

In case you happen to also be using a Sync Adapter like I am, you’ll also want to override a couple different things for that:


 <provider
            tools:replace="android:authorities, android:label"
            android:name=".content.SyncableContentProvider"
            android:authorities="com.sample.package.provider.debug.sync"
            android:enabled="true"
            android:exported="false"
            android:label="Your Label (Debug)"
            android:syncable="true" >

This lets us specify the correct authority and sets a different label in the Sync settings UI. Copy the sync adapter’s xml file that it’s your main/res/xml directory and place it in debug/res/xml. Modify it to reflect the correct authority:


<sync-adapter
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:contentAuthority="com.sample.package.provider.debug.sync"
    android:accountType="com.google"
    android:userVisible="true"
    android:supportsUploading="true"
    android:allowParallelSyncs="false"
    android:isAlwaysSyncable="true"/>

Throughout your code you’ll probably be referencing this authority string so it’s helpful to define it as a resource string especially now that you’ll need to differentiate between the debug and release version. So in both main/res/values/(somestringfile).xml and debug/res/values/(somestringfile).xml define:


<string name="sync_authority">com.sample.package.debug.sync</string>

You can now use this throughout your code without having to use any if statements or other logic to differentiate between the different versions. For example, in my sync adapter I use Google’s Tasks API and to get an auth token I call:


GoogleAuthUtil.getTokenWithNotification(mContext, account.name, "oauth2:" + SCOPE, null, mContext.getString(R.string.sync_authority), b);

The correct sync_authority string will be used depending on what build variant you’re running (debug vs release). Lastly if you happen to be using one of Google’s APIs (such as Tasks), remember to add a new credential in your developer console for your debug build variant since the package name is going to be different. Make sure the package name matches the one created by your buildType config settings – in this example it should be:


Package name
    com.sample.package.debug

That should do it!

One thing I have not figured out is how to make this work with IAB (in-app billing) api. Since your in-app products are listed with the main package name (com.sample.package in this example) – when attempting to make calls with the api, you’ll not see anything for your debug package (com.sample.package.debug in this example). And of course there are security errors if you try to retrieve skuDetails for example by using the com.sample.package string as the package name when you’re running the debug build variant.

References:

Android HTML in a TextView

The documentation on supported HTML tags and HTML usage is lacking in general so after some trial & error with some googling I got things to finally work correctly including links.

In my case I was working with text from a resource file, specifically items in a string-array. Here’s a snippet from my :


<item>
      <![CDATA[
            <p>The main purpose of this app is to help you get things done by focusing on the now. For more info on the techniques used and how you can get involved please visit the <a href=\"http://slamtastic.me/work/do-now/\">Do Now site</a> and <a href=\"http://slamtastic.me/category/productivity/\">Blog</a>. You can also follow on <a href=\"http://twitter.com/do_nowapp\">Twitter</a> and/or join the <a href=\"https://plus.google.com/communities/116626905003478130395\">G+ community</a> for feedback and beta access.</p>
            <br/>
            <p>It’s basically split into two parts: your ‘Planned’ items and your ‘Unplanned’ items. For more info, see the sections below about each list. Since syncing with Google Tasks is possible, this app can be used along with another app that focuses on long term tasks and goals as long as that app also syncs with Google Tasks.</p>
      ]]>
</item>

Notice the <![CDATA[ ]]> tag that surrounds the HTML text. You’ll need this unless your text is very basic and no parsing is needed. The other thing to notice is escaping the quotes in the anchor tags. Without this, when the string is parsed, you’ll end up with href=yoururl which is invalid and will not work.

Next is loading the text. You’ll need to use the HTML class to parse the string:

Html.fromHtml(someHtmlText)

You can set that as the text for TextView or save it to a Spanned type variable then set that as the text.

After setting the text using textView.setText(parsedHTML) use:


textView.setMovementMethod(LinkMovementMethod.getInstance());

Your TextView should look like this (noting the android:linksClickable and android:textColorLink attributes):


<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/text_primary"
        android:layout_marginBottom="10dp"
        android:linksClickable="true"
        android:textColorLink="@color/primary"
        android:id="@+id/help_child_description"/>

Now your HTML should be parsed correctly and links working.

(Android) Custom list item highlight

Here’s a simple and direct approach to customizing the background of a selected item in a listview:

First, in your list item layout add android:background="?android:attr/activatedBackgroundIndicator to your parent view. For example:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/drawer_item_height"
    android:orientation="horizontal"
    android:paddingRight="@dimen/default_gap"
    android:paddingLeft="@dimen/default_gap"
    android:gravity="center_vertical"
    android:longClickable="false"
    android:background="?android:attr/activatedBackgroundIndicator">
   
    <!-- View children here-->

</RelativeLayout>

Next, override the activeBackgroundIndicator style in your theme. i.e:


<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:activatedBackgroundIndicator">@drawable/activated_background</item>
</style>

You’ll notice we’re indicated a custom drawable to use: activated_background. Go ahead and create that in your drawable directory. It should look like this:


<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_activated="true" android:drawable="@color/row_activated" />
    <item android:state_focused="true" android:drawable="@color/row_activated" />
    <item android:state_pressed="true" android:drawable="@color/row_activated" />
    <item android:state_checked="true" android:drawable="@color/row_activated" />
    <item android:drawable="@android:color/transparent" />
</selector>

Obviously you can customize it further by setting different colors depending on the state. @color/row_activated is just a color that was defined in colors.xml: <color name="row_activated">#7986CB</color>.