In order to maximize sales of your application you'll want to ensure that your code will run across all the Blackberry JDE component versions, or at minimum you'll want to write code that is portable across the most popular Blackberry phones on the market: the Pearl, Curve, Bold and Storm and the various iterations of models within each line.

The main issue outside of the complexity of managing memory and laying out the screen components is that you want to have a single manageable code base that runs across Blackberry phones so you don't have to contend with several branches of code specific for each phone. You might think that you'd simply import the appropriate Storm touch classes, code the touch interface aspects of your app, compile and run to make your existing code work for 4.7.0. The problem is that shortly after you're done you'll see that your code will run on the Storm simulator but fail miserably for anything below 4.7.0 - the 4.6.x components and below don't recognize imports of classes built for 4.7.0.

Preprocessor Directives and Definitions


So how do we take our existing code, add the touch aspects, and have it compile in 4.6.x and below? This is where preprocessor directives come into play. In standard C and Java programming, preprocessor directives are invoked by the compiler as the first part of translation. For example, #include and #define in C and import in Java. In the context of Blackberry programming, the preprocessor directives will tell the compiler to import class definitions and perform statements within our code dependent on preprocessor definitions that we set up within the Eclipse programming environment.

For our example, we will use the preprocessor directives to tell the compiler to load the TouchEvent and VirtualKeyboard classes from 4.7.x. In order to do this within the Eclipse environment we have to do a bit of a hack by using the #ifndef (otherwise known as 'if not defined') directive as if it is a #ifdef(otherwise known as 'if defined'). We'll also configure the Eclipse IDE to provide the preprocessor definition which will write the appropriate config to the .jdp RIM project file without us having to manually edit it.

Eclipse Configuration


The current iteration of the Eclipse Blackberry plugin has the capability for preprocessor definitions built in, under the project properties. The settings can be found by clicking in the Eclipse menu on Project->Properties->Blackberry Project Properties and selecting the "Compile" tab. It will look like the image below:



If your Eclipse doesn't have the 'Preprocessor Defines' box then you'll have to update your plugin version to take advantage of this feature. Click the Edit button and add the following lines:

  • JDE_4_7_0

  • PREPROCESSOR



Click the Apply button and Eclipse will clean the project and rewrite the Preprocessor defines you just added to the .jdp RIM project file. Just as a sanity check, open this file and check the 'Options' line that is near the end. It should now look like this if the changes were appropriately made:

  • Options=-define=JDE_4_7_0;PREPROCESSOR



Adding Preprocessor Directives to Your Code


Now that you've configured Eclipse with the proper Preprocessor definitions you need to add the directives to your code so the preprocessor knows what to add and when. For our example we are going to add the code necessary to perform touch events and import the appropriate 4.7.x classes. First you want to import the classes to your program file, then surround the import statement with the directives,refer to the example below:


//#preprocess
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

//#ifndef JDE_4_7_0
/*
//#endif
import net.rim.device.api.ui.TouchEvent;
import net.rim.device.api.ui.VirtualKeyboard;

//#ifndef JDE_4_7_0
*/
//#endif

import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.MenuItem;
....


We're using #ifndef statements and multi-line comments to trick Eclipse into allowing the import statements without showing errors when you don't have the 4.7 components installed. As a result these statements will appear as comments in Eclipse but will load appropriately when the JDE_4_7_0 preprocessor definition is loaded. Note that you must have the #preprocess statement at the top of any file where you're using preprocessor directives.

Within your code blocks you'll also have to use this commenting approach around any statements dependent on the 4.7 components. Refer below to the VirtualKeyboard calls within the constructor call:


public SearchScreen(Search s){


super(DEFAULT_MENU);
//Necessary because by default keyUp events are disabled
UiApplication.getUiApplication().enableKeyUpEvents(true);
search = s;
myCallback = new ListCallback();
myCallback.erase();
myList = new ListField(0,Field.FIELD_HCENTER);
ingredients = search.getIngredientList();

//#ifndef JDE_4_7_0
/*
//#endif

vk = this.getVirtualKeyboard();
vk.setVisibility(VirtualKeyboard.HIDE_FORCE);

//#ifndef JDE_4_7_0
*/
//#endif
}


Now when you want to run the code using 4.6 or lower components just delete the JDE_4_7_0 preprocessor definition from the project properties and change the installed components to 4.6 or lower. You'll find that Eclipse won't generate any errors and the code will run as intended across devices.

Epilogue


Obviously there are other issues that plague Blackberry developers when it comes to cross phone portability. One issue is that of available phone memory which determines the number of persistent/normal object handles available to your program. For a great guide on managing memory, check out the Blackberry Memory Best Practice Guide.

Secondarily, you'll have to ensure that your application layout is portable across phones since the resolution is different between models. You'll find yourself having to check the resolution of the device within your code in order to position buttons, align text boxes, etc. for each device. In other words, there will be a lot of code that checks the screen width and height to layout the screen for each device similar to the code below that sets the font size for different devices:




width = Display.getWidth();
height = Display.getHeight();

if(width == 480 || width == 360)
fSize = 21;
else if(width == 320)
fSize = 18;
else
fSize = 16;

11 comments:

tony said...

First of All, thanks a lot for the example, it really helped out. I want to however note a typo in your code.

In "Eclipse Configuration"
You defined the preprocessor "JDE_4_7_0". However, in your code, you used "//#ifndef JDE_4_7 ". You need to have "//#ifndef JDE_4_7_0". So if you are using his example, make sure you include the "_0" at the end of your defines.

John Banks said...

@tony - Thanks for catching that one. I made the modifications to the code so anyone can cut and paste it in w/o problem.

tony said...

I'm having some issues with using preprocess to lock orientation of blackberry storm. Here is my code:

//#preprocess

package com.sasktellabs.app;

import net.rim.device.api.ui.UiApplication;

import com.sasktellabs.controller.Controller;
import com.sasktellabs.controller.NavigationController;


public class Cheetah extends UiApplication
{
/**
* The main method.
*
* @param args the arguments
*/
public static void main(String[] args)
{

Cheetah app = new Cheetah();
// setsup the nav controller and Controller.
NavigationController.getInstance().setApplication(app);
Controller.getInstance().setApplication(app);
Controller.getInstance().StartSearchThread();
app.enterEventDispatcher();
}

/**
* Instantiates the app.
*/
public Cheetah()
{

//#ifndef JDE_4_7_0
/*
//#endif

// Disable orientations other than the NORTH direction
int directions = net.rim.device.api.system.Display.DIRECTION_NORTH;
net.rim.device.api.ui.Ui.getUiEngineInstance().setAcceptableDirections(directions);


//#ifndef JDE_4_7_0
*/
//#endif

}
}

as you can see, I used the preprocess code to wrap around the getUi. getUiEngineInstance().setAcceptableDirections() call. However, I can't seem to get this to work properly. Either I'm not locking the orientation, or I can lock on my storm but any pre 4.7 builds give me an error with module getUiEngineInstance() not found error (meaning it didn't include the /**/ from the preprocess code). Any suggestions?

I've also checked my config.ini to include osgi.framework.extensions=net.rim.eide.preprocessing.hook and also checked the jdp file that in does indeed have Options=-define=JDE_4_7_0;PREPROCESSOR.

John Banks said...

@tony - I took a quick pass through your code and it looks correct. Did you do this when you switched to the pre 4.7 builds?(from the blog):"Now when you want to run the code using 4.6 or lower components just delete the JDE_4_7_0 preprocessor definition from the project properties and change the installed components to 4.6 or lower." Unless you delete that from the properties Eclipse throws a fit when you change components since the 4.7 classes you're trying to import don't exist in the 4.6 components.

By the way it follows that when you switch components back to 4.7 you add the preprocessor statement in again.

tony said...

@John - Yeah, I missed that line. That would make sense. I think I misunderstood how preprocessor's work. Now that I have more understanding, this seems very defeating since I constantly have to change a lot of settings around for each build. I guess this is just the way goes for now.

John Banks said...

@tony - it actually is a *bit* of a pain to make the change but don't be defeated with it. Realistically, you just have to delete or add that one line in the properties so it's not too bad. And you'll only have to do it when you change components - in my experience you tend to stay in one set of components for awhile, develop and finish the code there, then change to another set to work on other phone types.

If you have any other problems let me know.

ssaidwho said...

Hello,

Thank you for this post, it was really helpful. I wanted to note that, for whatever reason, Eclipse doesn't show "Blackberry Project Properties" in my view (even though I have the plugin installed and its a blackberry project). To get around this problem, if you open the BlackBerry_App_Descriptor.xml file with Eclipse, you can add Preprocessor Defines by clicking on the viewer's 'Build' tab. Alternatively you can open the file with a text editor (within Eclipse or outside), and modify the XML to add a Compile element to the properties as such (replaced < with & to make the XML show up):

&Compile OutputCompilerMessages="false" ConvertImages="false" CreateWarningForNoExportedRoutine="false" CompressResources="false" AliasList="">
&PreprocessorDefines>
&PreprocessorTag IsActive="true" PreprocessorDefine="JDE_4_7_0"/>
&PreprocessorTag IsActive="true" PreprocessorDefine="PREPROCESSOR"/>
&/PreprocessorDefines>
&/Compile>

I then made code changes as described. This worked for me.

Thanks again!
Steve

Anonymous said...

Hi,

Thanks for the post. It was really helpfull for me!

However I'm not sure i fully understand how the comment works.

Can you take me through the logic behind this code? Assuming I have declared the JDE_4_7_0 in properties

1 //#ifndef JDE_4_7_0
2 /*
3 //#endif
4 import net.rim.device.api.ui.TouchEvent;
5 import net.rim.device.api.ui.VirtualKeyboard;
6
7 //#ifndef JDE_4_7_0
8 */
9 //#endif

lines 2 uptill line 8 confuses me. Is it not supposed to be one big block of comment? How then does it get
executed if JDE_4_7_0 is defined?

Thanks

Dan

Anonymous said...

Hi everyone,
I'm working with BlackBerry Eclipse Plug-in version 1.1 and I`m encountering some problems regarding preprocessing, as I'm trying to set DIRECTION_EAST on the screen whenever the device supports touch technology. It does occurs with BlackBerry Software version 4.7 and forward.
I've followed the steps mentioned and unfortunately the preprocessing doesn't take any effects.
I enclose my code here:

//preprocess
..
//#ifndef JDE_4_7_0
/*
//#endif

// these are the instructions that doesn`t perform
int direction = Display.DIRECTION_EAST;
Ui.getUiEngineInstance().setAcceptableDirections(direction);

//#ifndef JDE_4_7_0
*/
//#endif


Besides, the application descripor file is correct, as it follows:

...






...

Any help with this?? Is it something that I have missed or done wrong??
Thank you very much in advance.

Regards,
Beatriz.

Beatriz said...

Hi eveyone,

I’ve already sent a post, but I think that it hasn’t been delivered properly. I don’t know why…
As I said before, I’m working with BlackBerry Eclipse Plug-in version 1.1 with the BlackBerry SW 4.7.0 version and I’m encountering problems with preprocessing my code in order to make the layout of the screen follow de “east” direction for devices with touch technology meanwhile for the rest of devices, the intended direction will be “north”. It seems as if the preprocessing doesn’t take any effect as the screen is always in vertical position.

My code is the following:

//#preprocess

//#ifndef JDE_4_7_0
/*
//#endif

int direction = Display.DIRECTION_EAST;
Ui.getUiEngineInstance().setAcceptableDirections(direction);

//#ifndef JDE_4_7_0
*/
//#endif


Also, the application descriptor file is correct, as you can see the definitions of the processing directives:









What can the problem be due to? What have I missed or done wrong?? For some of you the trick has worked successfully.
Any help will be appreciated.
Thanks in advance.
Regards,
Beatriz.

mihir said...

Hi, john
Where i can write else part i want to write some thing like this

#ifdef JDE7
class abc implements MagnetoMeterListener
#else
class abc

can you give me example for same

Thanks

Post a Comment

top