URLEncode With Objective C – The OAUTH Way

Coming from a PHP background, we should all be thankful to rawurlencode() from PHP! Here’s an Objective C version with OAUTH v1.0a requirements.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- (NSString *)urlencode:(NSString *)text {
    NSString *temp = @"";
 
    for(int i=0, max=[text length]; i<max; i++) {
        char t = [text characterAtIndex:i];
        int b = (int) t;
 
        if(
           t == (char) '.' ||
           t == (char) '_' ||
           t == (char) '-' ||
           t == (char) '~' ||
           t == (char) '#' ||
           (b>=0x30 && b<=0x39) ||
           (b>=0x41 && b<=0x5A) ||
           (b>=0x61 && b<=0x7A)
            ) {
            temp = [temp stringByAppendingFormat:@"%c", t];
        } else {
            temp = [temp stringByAppendingString:@"%"];
            if (b <= 0xf) temp = [temp stringByAppendingString:@"0"];
            temp = [NSString stringWithFormat:@"%@%X", temp, b];
        }
    }
 
    return temp;
}

Blackberry Coordinates From Cell Tower

I’m beginning to like coding in Blackberry since now an official JDE for Mac is available. Then I decided to have a look and prepare myself for some rather annoying but pleasant surprise from Blackberry’s JDE. To be honest, I don’t like Blackberry’s behavior of complicating simple things. But then I learned a lot from the codes.

Urbanesia is a location based service and therefore location is very important. I’ve been trying out a few ways to get the device’s location and after all the things I’ve tried, I resorted into plain GMM solution. Blackberry’s location API was too slow to get a fix on the device’s location. Nevertheless, the codes are included as well.

The codes should work well from Blackberry OS 5.0 upwards. Haven’t tried with older OS. You might want to wrap calling the methods inside a Thread so it won’t block the UI. My 2 cents about Threading in Blackberry, extend the Thread class, makes life easier.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package com.urbanesia.api;
 
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
 
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.location.Criteria;
import javax.microedition.location.Location;
import javax.microedition.location.LocationException;
import javax.microedition.location.LocationProvider;
 
import net.rim.device.api.system.GPRSInfo;
 
import com.urbanesia.utils.Log;
 
public class CellTowerLocation {
	protected static final int LOOKUP_TIMEOUT = 5000;
	protected static final int LOOKUP_TOLERANCE = 500;
 
	public static final boolean FORCE_LOCATION_UPDATE = true;
	public static final boolean DONT_FORCE_LOCATION_UPDATE = false;
 
	public static String getLocation() {
		Criteria ct = new Criteria();
		ct.setHorizontalAccuracy(1000);
		ct.setVerticalAccuracy(1000);
		ct.setCostAllowed(true);
		ct.setPreferredResponseTime(LOOKUP_TIMEOUT);
		ct.setPreferredPowerConsumption(Criteria.POWER_USAGE_LOW);
 
		String coords = "";
		try {
			LocationProvider lp = LocationProvider.getInstance(ct);
			Location loc = lp.getLocation(LOOKUP_TIMEOUT + LOOKUP_TOLERANCE);
 
			String lat = String.valueOf(loc.getQualifiedCoordinates().getLatitude());
			String lon = String.valueOf(loc.getQualifiedCoordinates().getLongitude());
 
			coords = lat+","+lon;
			Log.out("Coordinates - Exact Location: " + coords);
		} catch (LocationException e) {
			Location loc = LocationProvider.getLastKnownLocation();
			String lat = String.valueOf(loc.getQualifiedCoordinates().getLatitude());
			String lon = String.valueOf(loc.getQualifiedCoordinates().getLongitude());
 
			coords = lat+","+lon;
			Log.out("Coordinates - Using last known location: " + coords);
		} catch (InterruptedException e) {
			Location loc = LocationProvider.getLastKnownLocation();
			String lat = String.valueOf(loc.getQualifiedCoordinates().getLatitude());
			String lon = String.valueOf(loc.getQualifiedCoordinates().getLongitude());
 
			coords = lat+","+lon;
			Log.out("Coordinates - Using last known location: " + coords);
		}
 
		Log.out("Coordinates: " + coords);
		return coords;
	}
 
	public static String getLocation(boolean force) {
		if(force) {
			Criteria ct = new Criteria();
			ct.setHorizontalAccuracy(1000);
			ct.setVerticalAccuracy(1000);
			ct.setCostAllowed(true);
			ct.setPreferredResponseTime(LOOKUP_TIMEOUT);
			ct.setPreferredPowerConsumption(Criteria.POWER_USAGE_LOW);
 
			String coords = "";
			try {
				LocationProvider lp = LocationProvider.getInstance(ct);
				Location loc = lp.getLocation(-1);
 
				String lat = String.valueOf(loc.getQualifiedCoordinates().getLatitude());
				String lon = String.valueOf(loc.getQualifiedCoordinates().getLongitude());
 
				coords = lat+","+lon;
			} catch (Exception e) {
				Location loc = LocationProvider.getLastKnownLocation();
				String lat = String.valueOf(loc.getQualifiedCoordinates().getLatitude());
				String lon = String.valueOf(loc.getQualifiedCoordinates().getLongitude());
 
				coords = lat+","+lon;
			}
 
			Log.out("Coordinates: " + coords);
			return coords;
		} else {
			return getLocation();
		}
	}
 
	public static String getLocationGMM() {
		String coords = "0,0";
		int cellID = GPRSInfo.getCellInfo().getCellId();
		int lac = GPRSInfo.getCellInfo().getLAC();
 
		String urlString = "http://www.google.com/glm/mmap" + ConnString.getConnectionString();
 
		try {
			HttpConnection conn = (HttpConnection) Connector.open(urlString);
			OutputStream os = null;
			InputStream in = null;
 
			conn.setRequestMethod(HttpConnection.POST);
			conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); 
			conn.setRequestProperty("If-Modified-Since","29 Oct 1999 19:43:31 GMT");
			conn.setRequestProperty("User-Agent","Urbanesia Jajan Blackberry v1.0");
			conn.setRequestProperty("Content-Language", "en-US");
 
			os = conn.openOutputStream();
			WriteData(os, cellID, lac);
 
			in = conn.openInputStream();
			DataInputStream dataInputStream = new DataInputStream(in);
			dataInputStream.readShort();
			dataInputStream.readByte();
			int code = dataInputStream.readInt();
			if (code == 0) {
				double lat = (double) dataInputStream.readInt() / 1000000D;
			    double lng = (double) dataInputStream.readInt() / 1000000D;
			    dataInputStream.readInt();
			    dataInputStream.readInt();
			    dataInputStream.readUTF();
 
			    coords = Double.toString(lat) + "," + Double.toString(lng);
			    Log.out("Coordinates - Got from GMM: " + coords);
			} else {
				Location loc = LocationProvider.getLastKnownLocation();
				String lat = String.valueOf(loc.getQualifiedCoordinates().getLatitude());
				String lon = String.valueOf(loc.getQualifiedCoordinates().getLongitude());
				coords = lat+","+lon;
				Log.out("Coordinates - Using last known location: " + coords);
			}
		} catch (Exception e) {
			Location loc = LocationProvider.getLastKnownLocation();
			String lat = String.valueOf(loc.getQualifiedCoordinates().getLatitude());
			String lon = String.valueOf(loc.getQualifiedCoordinates().getLongitude());
			coords = lat+","+lon;
			Log.out("Coordinates - Using last known location: " + coords);
		}
 
		return coords;
	}
 
	private static void WriteData(OutputStream out, int cellID, int lac) throws IOException  {
		DataOutputStream dataOutputStream = new DataOutputStream(out);
		dataOutputStream.writeShort(21);
        dataOutputStream.writeLong(0);
        dataOutputStream.writeUTF("en");
        dataOutputStream.writeUTF("Android");
        dataOutputStream.writeUTF("1.0");
        dataOutputStream.writeUTF("Web");
        dataOutputStream.writeByte(27);
        dataOutputStream.writeInt(0);
        dataOutputStream.writeInt(0);
        dataOutputStream.writeInt(3);
        dataOutputStream.writeUTF("");
 
        dataOutputStream.writeInt(cellID);  
        dataOutputStream.writeInt(lac);     
 
        dataOutputStream.writeInt(0);
        dataOutputStream.writeInt(0);
        dataOutputStream.writeInt(0);
        dataOutputStream.writeInt(0);
        dataOutputStream.flush();
	}	
}

Trying Out Mac OS X Lion – Gold Release

This weekend is spent trying out and figuring out the latest Mac OS X evolution which is Lion. It’s my second time installing Lion, the first time was with the first seed released by Apple. This time is the so called Gold Release that will most likely be prime candidate for a full release.

I got this DMG from the usual suspects and while reading its installation instruction, I was glad to know that it doesn’t involve any DVD disc to do so. The DMG was already enough and on my 10.6.7 Snow Leopard, I mounted the DMG and followed the instructions. I choose to upgrade my Snow Leopard to Lion. To my surprise, it was dead easy.

The installer went ahead by copying the files needed for the real installation routine, after that it prompted me to restart. I followed through and the installation routine just does what it’s supposed to do with a very minimal intervention. The whole process took about 40 minutes to finish.

First boot was excruciatingly slow reaching my desktop. I figured I should reboot one more time and do a little analyzing. The second time it was on my desktop, I noticed that Spotlight is heavily indexing all of my files. A deal breaker indeed, it made my Early 2011 Macbook Pro 13″ harddrive felt increasingly shadowed by SSD drives. Here’s a screenshot of my Lion desktop.

Lion Desktop

Lion Desktop

If you notice on the bottom left, my Dock is showing 2 new icons just beside the Finder icon which are Launchpad and Mission Control.

Launchpad

Launchpad

Mission Control - Desktop 1

Mission Control - Desktop 1

Mission Control - Desktop 2

Mission Control - Desktop 2

Launchpad is like when you’re on an iOS device flicking through all the applications/games installed within your device. This indeed is a sign of a touch enabled Lion devices is not a hoax. Mission Control is what you get when you usually use Expose to switch between your applications, with Mission Control, you can also see all your desktops. Application can be dragged and dropped into any desktop you want. This is convenient, it takes logically partitioning your desktop a step further.

One of the first thing you would notice is that scrolling up and down is backwards. This is yet another indicator that Lion is already a touch friendly OS. To change this behavior, System Preferences is the place to go.

Scroll & Zoom

Scroll & Zoom

Since upgrading into Lion I have several applications not running the way it should be, here are the list of applications I have right now that are not working:

  • NX Client – Not Working
  • Tuxera NTFS – Not Working
  • Perian – Not Working

Performance wise, I am not too satisfied with Lion but hey this is not a full release, I hope Apple do get ahead with Spotlight, it’s ridiculously not cool. I’m gonna post updates along the way. Thanks for reading.

Mobile Trends – Looking Back 1 Year

I’m still fairly new to mobile development, just a little over a year. As I dig deeper, it just gets more and more interesting. This won’t be a technical writing like a tutorial but more to how the development scene has been evolving for the past 1 year. Putting it simple: Trends.

I started my mobile development efforts with Blackberry. Against all odds, I installed the SDK on a Windows virtual machine using Parallels Desktop. The experience developing using a virtual machine was painful. For long term use, it’s too slow and too awkward. Anyways, I managed to connect the Blackberry device with the IDE. So I created my first Hello World with it. It took me a great deal of my time learning about the platform. Most of the key information are for paid developers unfortunately and sadly enough, BIS is needed and I didn’t have it. A big roadblock for a newbie developer.

Being dissatisfied with Blackberry, I moved on to iPhone. I got myself an iPhone 3G and boy that was the worst iPhone I’ve ever played with. Why I say this, the experience is just sour with iPhone 3G. The hardware couldn’t keep up with apps that are demanding. However, it was even worse with its SDK. So I downloaded and installed Xcode + iPhone OS SDK (at the moment). I couldn’t get apps to be deployed to the iPhone without a paid ADC membership. Well being a single minded person, I jailbroken the iPhone and followed tutorials to get it to work with my intentions.

The most powerful thing an iPhone has to offer is its native development approach. They are using Objective-C and that directly translates into better performance (supposedly) compared with Java platforms. Okay I surrender the argument, Android can use NDK instead of SDK to develop BUT only in Android, kudos to Google! Back to iPhone, I managed to get my first Hello World running. The next step was to study Objective-C in depth. The result: none. I hated pointers in C and still hate it today. So I didn’t learn Objective-C at that time, instead I came across Titanium Developer.

Titanium uses a wrapper API on top of Objective-C like what Objective-C is to C. The programming language is JavaScript so a web developer like me got comfy instantly. At the time, the support was still limited both in iPhone and Android however it’s enough to built a simple Augmented Reality application. So I made one and boy webkit’s CSS 3 3D transformation were a lifesaver! Thanks for this Webkit Developers, you guys rock! With Titanium, it enabled me to focus on the app instead of the platform and that’s the key point!

Although my first experience developing in iPhone left happy memories, I wasn’t satisfied with its distribution in Indonesia. No one was using it so I thought why not try the Green Robot, the userbase at the time can be rounded to 0 meaning actual users were very limited. I sold the iPhone and bought a Nexus One. First impression: YEAYYYYYYYYYY!!!!!!!!!!

I was completely stunned how smooth an Android was. A Nexus One is Google’s example of how every Android device should be and the bar was set very high! The quality of the hardware was pristine as do with any HTC devices able to run Eclair without much effort. I eventually upgraded it to Froyo and was really satisfied with the phone’s performance. However, although Android can be a developer’s best friend immediately, still the UX was way off compared to iPhone. It didn’t bother me much, it’s a motivation actually to be better than average.

Immediately I started learning to develop on an Android and must I say, the learning curve was not as I expected. I never coded in Java other than Hello World in Blackberries. I was comfortable because syntax-wise, it was not quite much different than PHP. The 1 thing I was grateful in Java and PHP is Garbage Collectors. I mentioned before that Android has its own NDK allowing developers to code in pure C if needed so performance of an Android app is actually tweakable.

Now I’m using an iPhone 3GS and boy it was one of my most memorable gadget buying decision. The performance woes I experienced with iPhone 3G was not present with 3GS. The experience of a proper Apple device is just magnificent. Apple focuses on experience and the consumptive nature of any perfectly normal human beings and I was sold lol.

Enough with hardware, what I really want to write about is software. An example of superb apps in my opinion are Wunderlist, Evernote, Angry Birds and Instagram. This is limited only to my knowledge and the apps I have used before in any platforms so you are welcomed to debate.

Wunderlist is a To Do list organizer and it’s available in iOS, Android (beta), Chrome Webapp (beta), Macs and Windows. This is a prime example of how an app is bringing its experience agnostically across different platforms. This particular app is made with Titanium Developer which makes its development efforts actually faster than native developments. Apart from Wunderlist’s functions as an app, it showed a glimpse of the future.

After Wunderlist, there’s another productivity booster I can’t live without which is Evernote. Note taking has never been so easy and because it’s cloud driven, the notes are immediately available. Need I say more about this app? It’s just fantastic, lifesaving and above all, all my data is available 24/7 from any device I access it with. Evernote is amazingly available for iOS, Android, Blackberry, Palm Pre/Pixi, Windows Mobile, Macs, Windows and Chrome Extension.

Next up is that hyper-popular game named Angry Birds. Another example of cross platform success. Angry Birds is available initially in iOS devices but now has widen its reach to Android, Windows and Macs. A clear example of how microprices (sub $10) apps/games flourish. I’d pay for this game without even thinking about it because it’s damn cheap and I can play it in any platform I have in my hands at any moment. The experience with multiple platforms does not a change a bit, gameplay is consistent and boy its fun to play with.

Last but not least, this app is only available with iOS but has instantly received success. None other than Instagram. The app is a photo sharing app instantly enabling the average person to get an experience as a professional photographer. Okay it’s quite shallow but it’s simple and less is more I must say! Instagram is only available for iOS but now opening up its API to be used by developers. With that many photos from millions of users, I must say it’s an interesting API to play with. They are fishing for creativities and innovation from developers like you and me to use their data and turning them into food on the platter (information) for users.

If you noticed, I didn’t talk anything about monetizing apps because the ecosystem is not there yet, at least if you’re looking into monetizing from users. Only iOS I say have the best monetizing platform, they have paid apps and in app purchases while others still only offers paid apps. So I’ll leave it for another blog post.

The conclusion is as a mobile developer, I must be as agnostic as possible when it comes to platforms. Being good enough in 1 platform is not good enough. With platform fragmentation rates very high, a mobile developer need to have a clear understanding of the concept of experience. Tech stuffs I say is geeky and very interesting but it’s not enough to win over users. Futuristic is cool and we’re getting there ;)

Sphinx – Fulltext Search Engine – Part 1

OLYMPUS DIGITAL CAMERA

It has been a few weeks after my first encounter with this Egyptian named gem called Sphinx. At first glance, it’s complicated when looking at an already made sphinx.conf. However, after careful redesigning and re-tinkering, it turns out to be one of the most flexible and yet light fulltext search engine available today. There are others but nothing as light, fast and sleek as Sphinx. The cold truth is that Sphinx is supporting SQL based databases as far as I know. Since Urbanesia is already using MySQL as our backend, we’re lucky.

The first and most difficult part of learning Sphinx is it’s installation routine. Numerous times I have failed compiling Sphinx on my Macbook and also on CentOS servers. That made me stayed away too far from it. So after a few Googling sessions, I thought it was time to tame the beast. First step was to compile Sphinx on my Macbook.

What you’re gonna need are:

  1. Sphinx source code provided here. I downloaded the latest 1.10 Beta version, spoilers: Realtime Indexes :)
  2. expat library provided here.
  3. libiconv library provided here.

Where you’re all set, we’re gonna go ahead and start the fiesta. Just a note, this tutorial is downloading everything to /opt/sources and installing everything on /usr/local directory. You’re free to tinker.

    sudo -s
    cd /opt/sources
    tar xfz expat-2.0.1.tar.gz
    cd expat-2.0.1
    ./configure --prefix=/usr/local
    make && make install
    cd ..
    tar xfz libiconv-1.12.tar.gz
    cd libiconv-1.12
    ./configure --prefix=/usr/local
    make && make install
    cd ..
    tar xfz sphinx-1.10-beta.tar.gz
    cd sphinx-1.10-beta
    ./configure '--prefix=/usr/local/sphinx' CPPFLAGS="-I/usr/local/include
    -I/opt/local/include -I/Applications/xampp/xamppfiles/include
    -I/Applications/xampp/xamppfiles/include -arch i386" LDFLAGS="-L/usr/local/lib
    -L/opt/local/lib" 'CFLAGS=-O -arch i386' 'LDFLAGS=-arch i386' 'CXXFLAGS=-O -arch i386'
    make -j4 install

So you now have successfully compiled Sphinx and installed it to your Macbook. In any case, as long as it’s a Unix flavored OS, the routine is basically the same. Only in Mac OS X Snow Leopard I’d have to put the compiler in 32 bit mode because it mistakenly overridden all flags to 64 bit if not.

The next part of the tutorial will be about generating your own sphinx.conf. Until then!