Sunday, September 26, 2010

Use the BlackBerry Issue Tracker to find bugs

I don't know when BlackBerry start opening their issue list for the developers, recently I just know this service. This is a great service, you can browse, search and submit the Blackberry issues.

Here I would like to share my experience how to use the Issue tracker:

First go to BlackBerry Developer Zone, register an account, use this link:
  https://www.blackberry.com/bdsc/?lang=na#login

After login in, in the left part of the portal, click Resources tab, it will expand several sub links, then select "Developer Issue Tracker",  then click  link "Submit an Issue", finally your will enter the BlackBerry Issue Tracker portal.

For example, to identify an BlackBerry OS 5 SMS issue, I found a bug which reported the exact same issue, which is very helpful.
JAVAAPI-553:
Java APIs
   invokeApplication() Ignores PayloadText for Populating SMS Text Message
Created: 19/Oct/09 10:44 PM   Updated: 07/Jun/10 05:50 AM
DevTrack ID: 360769
Fix Version/s: None
App Build Number: 5.0.0.224
Device: Bold 9000
Component: --
Description: When calling Invoke.invokeApplication() and passing TextMessage arguments, the PayloadText is ignore when it should be used to populate the body of a new SMS message.

You will be surprised that there are some many open issues for different blackberry OS.
So I will suggest you to go to the Issue Tracker if you want to confirm a BlackBerry device issue.

The incompatible issues of BlackBerry OS 5

Recently I realize that BlackBerry OS 5 has more and more incompatible issues with 4.x, usually a feature works on pearl, curve, bold (4.6), but does not working on bold 5.0, which is very disappointing.

Here I just make a list of incompatible issues that I found recently:

1. BACK key issue
In 4.x, the BACK key value mapped in MIDlet is 27, I tested on 8100/8300/8900, this key value is the same: 27. But I just found in Bold with OS 5.0, the BACK key is not mapped into MIDlet at all, the MIDlet can not get the BACK key event.

2. SMS send issue. When you launch the BlackBerry native Message application to send SMS using Invoke class, you can pre-populate with phone number and text message, it works in 4.x, but does not work on 5.0, it is a know issue of blackberry 5.0, the message body is empty. Please check this link for details.

3. Retrieving CellID issue. We know that using GPRSInfo we can get phone's Cell-ID, but in 5.0 you will get the wrong id if you use the same method, this is because for 3G network, you need to use different method, how complicated it is!

4. Icon issue, I found in OS 5.0, you can set the rollover icon the jad file, and blackberry will recognize it even if your application is MIDlet, but I found you need to use JDE 5.0 to build your app; if you use JDE 4.x, it does not work.

I feel disappointed about BlackBerry platform, since I feel 4.2 - 4.6 even 4.7, the OS are quite consistent with each version, but in OS 5.0, it seems this is a big difference with previous ones. If OS 5 look like this, how can we trust OS 6?

Sunday, September 5, 2010

Be careful to use "Class.forName()" in J2ME

A couple weeks ago, I made another mistake: I tried to use Class.forName() method to solve the multiple platform issue, but unfortunately it did not work on the actual devices due to the issue caused by the obfuscation. This is my another blind spot, because of my ignorance of J2ME obfuscation.

Scenario
I need to provide an API to support multiple mobile platform, for example: Nokia, Blackberry, and simulator, etc.
What I implement is pretty easy:
  • define an interface: Service
  • Implement the Service interface for each mobile platform, for example: NokiaService, BlackBerryService, SimualtorService
  • At the build time, inject different Service class file in the package.
  • At the run time, the application use the Class.forName() to create the Service objects.
The snippet code looks like this:
public Service createService(int device)
 {
    Service service = null;

    if( device == NOKIA)
    {
        service = Class.forName("NokiaService").newInstance();
    }
    else if( device == BLACKBERRY)
    {
        service = Class.forName("BlackBerryService").newInstance();
    }
    else if(device == SIMULATOR)
    {
        service = Class.forName("SimulatorService").newInstance();
    }
    else 
        service = Class.forName("GenericService").newInstance();

     return service;
 }

Here I use a factory pattern to support multiple platform, no need to use preprocess, sound pretty simple, right?
But I found the above solution only works on BlackBerry platform, on other J2ME platform, the application will throw the ClassNotFound Exception.

The reason of failure
The problem is in obfuscation phase, we usually use Proguard to do preverification and obfuscation for the J2ME application. The proguard will remove the unused class file. (for detail please check this link ) In my solution above use class.forName() by passing different string values, which is not recognized in Proguard. For example: in Nokia platform, the NokiaService.class is used, but Proguard did not find the NokiaService.class is explicitly reference in the java code, so it think it is unused class file, then remove it from the final package. Then it cause the ClassNotFoundException.If you don't use obfuscation, the application works, but it is really rarely the commercial application does not have obfuscated.

But why it works on BlackBerry platform?
Because Blackberry is quite different with other J2ME platforms, it requires it own preverification and obfuscation using its own RAPC compiler. And I found that in Blackberry application package it usually keep all the class files in the package, which is different with the Proguard. That is the reason why it works in BlackBerry platform

Solution
I have to rewrite the above code, remove all the Class.forName(), replaced with the explicit method call.
To support multiple platform, I use javaassit to adjust the createService() method for different platform, while you can use pre-process if you want, even I really don't like the J2ME pre-process, because it will bring other more complicated issue in your application.

Conclusion
Class.forName() seems the only reflection that is support in the J2ME platform, but actually it will cause the problem during obfuscation phase, try not to use the Class.forName() in your J2ME application.