Thursday, May 17, 2012

Configuring ProGuard for an Android project

I've done a few Android projects and I find that when I start pushing out obfuscated binaries often I have to spend quite a bit of time debugging my proguard.conf file to get rid of all the new crashes :)
For this reason I've created this Android proguard.conf generic starting point template. If you've know any other common config lines let's have them and I'll update this post accordingly.

-dontpreverify
-optimizations !code/simplification/arithmetic
-keepattributes *Annotation*
-printmapping AppClassMap.map

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider

-keep class android.support.v4.** { *; }

-keep public class * extends android.app.Fragment
-keep public class * extends android.support.v4.app.Fragment
-keep public class * implements de.akquinet.android.androlog.reporter.Reporter
-keep class com.google.android.apps.analytics.PipelinedRequester$Callbacks

-keep public class * extends android.view.View {
    public (android.content.Context);
    public (android.content.Context, android.util.AttributeSet);
    public (android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}

# Keep serializable classes and necessary members for serializable classes
# Copied from the ProGuard manual at http://proguard.sourceforge.net.
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient ;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

-keepclasseswithmembers class * {
    public (android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public (android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers class * implements android.os.Parcelable {
    static android.os.Parcelable$Creator CREATOR;
}

-keepclassmembers class **.R$* {
    public static ;
}

-keep public interface com.android.vending.licensing.ILicensingService

-keepclasseswithmembernames class * {
    native ;
}

-keepclassmembers class * extends java.lang.Enum {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# Removes all calls to Log. Delete the methods you want to keep.
-assumenosideeffects class android.util.Log {
    public static int v(...);
    public static int d(...);
    public static int i(...);
    public static int w(...);
    public static int e(...);
    public static int wtf(...);
}

# Removes all calls to Log. Delete the methods you want to keep.
-assumenosideeffects class de.akquinet.android.androlog.Log {
    public static int v(...);
    public static int d(...);
    public static int i(...);
    public static int w(...);
    public static int e(...);
    public static int wtf(...);
}


-dontwarn **CompatHoneycomb
-dontwarn android.support.v4.**
-dontskipnonpubliclibraryclasses
-dontusemixedcaseclassnames

Monday, April 02, 2012

Setting it free

After making my first million :) I've decided that my Slashdot Reader Widget should be free. There are no annoying adds or anything else to lessen your experience - just the fully functional version for you to enjoy at no cost.

Saturday, January 21, 2012

Slashdot Reader Widget for Android - Maintenance

As soon as I released the original version of the Slashdot widget, I realized  that Android 3.0+ (honeycomb and ice cream sandwich) allows natively scrollable widgets (at least in the vertical direction) and this is much nicer on bigger screens, no such luck for Android 2.3 (Gingerbread) or prior versions of course.

The nice thing about Android and the Market Place is that it's relatively easy to work around this using the android:minsdkversion and android:maxSdkVersion elements of AndroidManifest.xml.

At this point I've developed 2 versions of the widget.

Version A:
- Targets Android 2.2 & 2.3 AndroidManifest.xml contains:
<uses-sdk android:minsdkversion="8" android:maxsdkversion="10"/>
- Uses custom arrow buttons for scrolling and switching between stories

Version B:
- Targets Android 3.0+ AndroidManifest.xml contains:
<uses-sdk android:minsdkversion="11"/>
- Uses ListView backed by a Collection

I did a build of both and publish them both concurrently in the Market Place - no problem :)

Wednesday, December 14, 2011

Slashdot Reader Widget for Android now available

I was shocked! 

Imagine there used to be no Android widget for Slashdot, simply unthinkable! I learned this when full of confidence I looked for one on the Android Market place and came up with nothing. I’ve been a Slashdot reader for years, I’d even go as far as to say that ./ is then only source of news I check regularly, and now this. 

There were plenty of Slashdot branded RSS reader apps but no home screen widgets. This horrible oversight has now been remedied, I’ve worked relentlessly over the past few weeks and last night (at around 2PM Sydney time) I’ve published my masterpiece. It’s only 99c so go get it. And if you have an iPhone then throw it away, get your self the latest Google phone and then get the widget :)

Long time no posts…


It has been quite a while since I’ve last put up a post. Much has happened since then.

  1. We’ve sold Cotopia so this blog is under my own name a no longer under the “Cotopia” name. All the posts are still here, just under a different heading
  2. I’ve made my peace with Maven (still hate Maven / Eclipse RPC integration) and use it on all my projects by default :)
  3. I’ve moved from JavaME to mostly Android and iPhone development and this will inevitably be reflected in the content of this blog

Wednesday, February 17, 2010

Maven and Eclipse RCP aka taking a trip to hell

Trying to get Maven and Eclipse RCP to work together to produce a build has been a complete nightmare. A member of my team spent a week trying to accomplish this feat and the end result has been hindering development ever since. Every time the plugin dependencies change, which in a young project is quite often, we're forced to update number of files by hand to accommodate the build process, which is fairly complex so that only one person on the team really knows what the hell is going on. I wouldn't believe how difficult something like building an RCP app with Maven can be, if I didn't live through it. Very frustrating stuff. Especially given that we're all quite happy with the way the actual RCP application has turned out.

Thursday, January 07, 2010

Maven ...

It seems one cannot get away from Maven now a days. In my current job as well as in my new job (which I start in a few days) we'll be using Maven to build and manage projects.
While Maven is quite nice in theory the plug-ins for it leave much to be desired in many cases. So without further delay here is a quote of the day by a colleague of mine:

"I hate Maven and the open source community!"

This made me laugh out since we use (pretty much exclusively) open source tools and software (NetBeans, Eclipse, GlassFish etc.) to build and run the business. But nevertheless, after a few days of hell trying to implement release management using a combination of Maven and Hudson plug-ins, universal hatred is what we have :)

Wednesday, December 23, 2009

A brush with Eclipse RCP

In my current job I seem to do quite a bit of UI work. The nice thing is that since my company is a start-up, the possibilities (in terms of technology at least) are unlimited. In the last year I've written GUIs using C# & WPF, Swing, and JavaFX. This time we were looking to create a 'system monitoring application' which should be able to present different types of information:

  • Tables
  • Graphs
  • Charts
  • Trees
  • etc...
The application also had to be easily extensible. While I personally have a fair amount of experience in GUI development, my two junior colleagues have done much less UI work. So it was just as important that the technology we choose has a gentle learning curve. Given a 4 week sprint we don't have much time to 'waste'. I have evaluated our options:
  • JavaFx: low level, lack of tools and out of box components
  • Swing: low level, good tools
  • SWT: low level
  • NetBeans platform: have personal experience
  • Eclipse RCP: unknown
It was clear that given the extensibility requirement we needed a platform. It came down to a choice between NetBeans Platform and Eclipse RCP. In the end I chose Eclipse RCP because I was able to step through this tutorial with complete ease and I felt that even though I have experience with the NetBeans platform my team mates would be faster in picking up the Eclipse RCP way of doing things.

Now, a month later, I have to say that I believe that my decision was the right one. After 3 days of tutorials and reading we were ready to go. Ultimately we have created a UI which is modular (with multiple self contained plugins), looks and feels the way our client expects, and will be easy to extend. In addition, majority of the actual UI work (using JFace, SWT, databinding, Eclipse RCP APIs) was done by my colleagues while I focused on the data models.

While I would take the NetBeans IDE over the Eclipse IDE for most things I am quite happy with the way our RCP based project turned out given the requirements.

Thursday, October 01, 2009

Sending GlassFish java.util log records to Chainsaw - no problemo

To send Java log records to from GlassFish to chainsaw we need to first translate the LogRecords (from java.util.logging) to LoggingEvents (used byt the log4j framework and accepted by chainsaw). Then also need to publish the resulting LoggingEvents to Chainsaw over a socket.

Here is how I do it:

* Copy ChainsawHandler.jar and log4j.jar into GLASSFISH_HOME/domains/domain1/lib/ext

* In Glassfish admin web console under: Application Server/Logging/General/Log Handler enter:

au.com.horseshoelane.logging.HSLChainsawLogHandler

* In Glassfish admin web console under: Application Server/JVM Settings/JVM Options/ add a new JVM Option:

-DchainsawPort=4447

this is the port to which Chainsaw clients can connect

* Restart GlassFish

* Configure a new SocketHubReceiver in Chainsaw that will connect to the chainsawPort

In case you are curious how it works or want to add functionality or fix a bug here is the source.

I would like to thank my current employer HSL for allowing me to publish this work - which they have sponsored in the form of my paycheck :)

Wednesday, September 16, 2009

JavaFX + WebStart + Web Services + GlassFish = One cool client app

In this post I will give an overview of the architecture that I've used to supply a connected thick (JavaFX) client application to a customer.

Here is the scenario: our company has an important customer who wishes to access and view some real-time data related to their business.

After some thought we've decided that the ideal platform for the client app is JavaFX (eye candy), the client deployment method is WebStart and we'll provide the data to the client via a SOAP Web Service. Easier said than done it turns out :)

There are a few issues with this set-up.

CLIENT:
The JavaFX client app can be written without major problems (see my previous posts about my beef with JavaFX tools) but I've found it best to create separate Java module to handle the WS communication. This is also useful since Maven doesn't seem to be able to build mixed source trees. Therefor the client app is composed of two separate JARs:
- Java library to handle WS client code generation and some utilities that are easier written in Java
- JavaFX GUI client that depends on the Java library

SERVER:
Simple enough Web Service deployed on GlassFish v2.1 JavaEE 5. Nothing special to note here.

DEPLOYMENT:
This was one of the trickiest parts. Since we have a number of servers (dev, test, stage, production, etc.) and we want a client which is downloaded from a specific server to connect to the WebService running on that same server. This we achieved by using a servlet to dynamically generate the JNLP file for the WebStart deployment. The servlet plugs the correct values into the JNLP for two things:
- where the client jars are located (i.e. codebase)
- a run-time property for the client specifying the WS location
The client (once launched) uses the WS location property to connect to the correct web service.
The servlet gets this information from system properties which can be easily set using the GlassFish web admin console. This means that we compile the code once and deploy it to any GlassFish server and all works well as long as we don't forget to add the two properties to the server.