You are currently browsing the archives for the iPhone category


Mobile Products & Handhelds Landscape

It’s been a few weeks after the whole world said their good byes to Steve Jobs, the iconic leader any startup/company should aspire to have. Everyone was in awe for what he did but mostly for what he didn’t do I suppose. He shaped the mobile landscape as we know today and for the years to come.

I believe strongly that mobile developers are candidly smart but also stupid at the same time, this includes myself. We are smart because we embrace a whole new paradigm and concept in programming that is actually still maturing. There is no one size fits all platform that will deliver everything a developer would need. The most stupid thing of all is actually focusing only on a single platform instead of the product.

While implementing a fresh way to develop mobile products, a notable early stage investor here in Indonesia told me that the technology I was implementing is still 2-3 years ahead of the industry. He was damn right in saying, “What’s the point? Going native is still the answer (for now)“. In spite of all cross platform goodness, there’s always a catch.

So why do any developments I said to myself? It’s just a waste of time and energy because it’s not an easy task to focus on different platforms at the same time. UI on every platform is different whether programmatically or its actual visual equivalent when users see them. I just can’t see any single solution will ever be ready for prime time in the near future. This being said by someone who has coded and NOT by analyst or writers who never coded their whole lives.

Anyways, the distant future is not so distant after all if you got cash for it. Just like the rest of the population, getting a US$ 500+ device is just too expensive. Although here in Jakarta, the trend is the higher the merrier for shops and buyers, it does not cater the whole population. People want first class products even if the could only spend less.

Premium sound premium because other devices make them look & feel premium. The physical properties of a device is the first thing anyone will notice. Nowadays form factors are suited for your thumbs and the way devices look these days are increasingly (subjectively) “better” with at least 10 years ago as a comparison. Devices don’t have explicitly visible antennas, they’re also getting smaller, lighter and the batteries although Internet connected most of the time still lasts longer relatively.

Cameras and phones is a match no one would argue and now 2 Megapixels is what you get at least. Although the quality won’t be that of pictures taken from a pocket camera but the technology is keeping up. We see phones sporting 8 Megapixels lenses from big names that used to be premium. Not to mention the success experienced by Instagram clarifies the argument even stronger. Remember those cheesy frames when you got your first Nokia camera phone, unnoticed and unaware, that’s Augmented Reality in a somewhat more primitive conceptualization.

Processors are getting double its core and power every year but sadly, not so with applications. I see a lot of time, software as an actual performance-hindering component even through upgrades of more advanced specs. What we can still be thankful is cheap memory (storage). You can easily get an 8-64 gigs Mini SD Card for at least $ 12.

So yes hardware is getting more powerful but the price is still a major barrier for end users to enjoy their own devices. If the device has a bitten Apple logo in it, people are used to paying premium, it is a premium device with all its glory. Coupled with a great recent iOS 5.0 release, it’s only gonna get better and better delivering the needs and wants of the whole market.

Android is catching up and has recently dethrone iPhone as the number 1 best selling smartphone in the world. What does this mean to developers and end users? Here’s a few pros and cons about Android as a platform:

Cons:

  • The User Experience is plain and prone to rather extreme iterative changes for every Android version.
  • Due to inconsistency in its User Interface, for each new version boasts a whole new look and it really is causing more problems than solutions, even though functions are defined constantly.
  • Dalvik is a great JVM with incredible clarity for Garbage Collectors. The report of freed memory by GC is actually very demotivating. Try inflating sub views, you’ll see why.
  • Doesn’t run well at all for devices < 800 MHz ARM processors. Samsung Galaxy Mini is a best seller, due to its popularity it can lead first time Android end users to associate Android with lag and unresponsive behaviors.
  • Multi threading is an alienated term for asynchronous. Sure there are classes to do this efficiently but this knocks down more creativity as do with most of C derived languages.
  • Fragmentation of different versions of Android makes developers support the lowest acceptable API level and end users stuck with whatever the handset maker offer.
  • Handset maker more often than not can’t keep up with Google’s amazingly fast iterative updates.
  • Free as in free beer, “Google Experience” devices will cost OEMs and or handset makers.
  • Quality apps in terms of UI/UX are nothing at all in quantity compared to iOS, Android is ok but not beautiful. Very subjective and open for debate.
  • A very dismal post-sales options to get upgrades to newer Android versions even if the device is still on warranty. After-market ROMs are available but this NOT the case with end users, still need guts and technical knowledge although I know a few non-technical friends of mine who does it almost naturally.
  • A very insecure platform! Don’t ever root an Android if you’re not up for its risks.

Pros:

  • Any developer with a spare time can always build their own version of Android. Customizable deep to kernel level, a talented developer can do magic with it.
  • Knowledge is available everywhere on the Internet.
  • Java is a relatively more well known language.
  • Layout is very flexible thanks to XMLs, seriously this is the first time I’m grateful of XML lol.
  • The growth chart is amazingly exponential, currently already topping off the iPhone.
  • Lets mid to low market to have a go at touch screen phones that is always connected. Opens up new possibilities especially for educating the general population about being online.
  • Because of looser supervisions of Android Market, it makes a great playing ground to test out new ideas, even half baked and see how the market responses.
  • Best practices are commonly available and design patterns in Java is very strong, one can be ready for prime time in no time.
  • Although heavily fragmented, developers are often given the option to adopt new frameworks available in higher API levels with a sort of compatibility library to enable them on lower API levels.
  • The kind of technology embedded into Android’s stack is already very extensive and very well though of although I have found some cases like a Multipart HTTP request library is only available if you use third party libraries or by making your own methods. Easily forgivable though in contrast.

There is still more to add to the 2 lists above but the ones written are the ones I feel worth noting. Other platforms have their own pros/cons but as any data will show, Android is topping the smartphone market and that’s a fact. It is the future, especially here in Indonesia. Due to Android’s nature of being open, adopting it is not so much a trivial task.

In China, Android is modded very heavily to suit China’s own needs for a smartphone. Most of the effort are made possible again because of Android Open Source Project (AOSP). Why can’t we do this for Indonesia? With or without the government on our back, we have a great market. It’s puzzling to not see an Android made by Indonesians being sold to Indonesians when we as Indonesians are well know for our desire and passion of making technological advances out of nothing. Wajanbolic is none other the best example.

We owe this to ourselves! As a person involved in the tech world of Indonesia generally, I applause Nexian for its bold efforts in having a very strong C/C++ team of developers to mod its own MTK feature phones. It’s not an easy thing to do but in the end of the day, end users want more beyond its low price. I truly hope Nexian will set an example with its Android phones.

Being a dreamer, one can visualize a very mobile and an actually high tech tomorrow without end users having to fuss with technical jargons and or spec to be persuaded to buy a smartphone. Like any startup will tell, a good product will market and sell itself. We can still empower and influence the market, it’s just a shame if we see this kind of success and control not in the hands of local companies. We know what our market need, not to mention their wants. Look at Google, Facebook, Groupon, etc, their investing so much to become hyperlocal and we just stood there and made to watch as our great market is slowly but surely taken over.

Read the paragraph before with some lime and a pinch of salt, my purpose is simple, it’s the future and nothing else. If anyone is reading this and somehow is disagree with my writings, the comments below is open for anything.

Anyhow, it would be great if we can analyze different user behaviors in a collective way. This will benefit us all without sacrificing privacy though. Although here in Indonesia nobody gives a damn about privacy but I still believe in ethical means in doing it. I’m just not sure the industry itself is ready. I have some data and would love to share with yours. Let’s be smart about this.

All and all, the mobile landscape in Indonesia still very early in its infancy, we have the upper hand of knowing what the market like and how to capitalize on it. Let’s make that disruptive force coming from us and of course for us. Aren’t you tired of making a living outside Indonesia because our market is still not ready yet? Well it’s gonna happen soon and you better be ready for it. I’m game, are you?

Indonesians like to buy things they don’t need, they buy what they want as proof of their existence and identity. RBT is a great example and generates a sick load of revenue. In app purchase is the way to do it + bragging rights.

HMAC-SHA1 Base64 Result With Objective-C

A few days of hard done nights were all inspired by faulty encodings. Talk about “Hello World” experiences LOL. Keeping things in mind, to really smooth things up between Objective-C and PHP, in any Objective-C functions needing to encode/decode strings like PHP, here’s the encoding type:

NSASCIIStringEncoding

Do not interchange this with any other or things will go wrong :( Here are snippets to generate HMAC-SHA1 hashes in its Base64 form encoded correctly for OAUTH v1.0a authentication.

The Base64Transcoder library is the work of Jonathan Wright, available at http://code.google.com/p/oauth/. Cheers!

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;
}

OAUTHnesia Client for Objective-C

Okay for the last few hours, I’ve been learning how to code in Objective-C and the first result is an OAUTH client for Urbanesia. I haven’t tested thoroughly though. The class basically wraps POST & GET requests to Urbanesia with OAUTH requirements.

Instantiating the class, you will have to provide Consumer Key & Secret obtained from Urbanesia. The current implementation requires User Key & Secret for every requests too. Future release of OAUTHnesia will include non Use Key/Secret methods and XAUTH.

You will have to do the HTTP connection yourselves with your own codes, OAUTHnesia only wraps the request with proper OAUTH requirements.

Base64Transcoder.h

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
/*
 *  Base64Transcoder.h
 *  Base64Test
 *
 *  Created by Jonathan Wight on Tue Mar 18 2003.
 *  Copyright (c) 2003 Toxic Software. All rights reserved.
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 *
 */
 
#include <stdlib.h>
#include <stdbool.h>
 
extern size_t EstimateBas64EncodedDataSize(size_t inDataSize);
extern size_t EstimateBas64DecodedDataSize(size_t inDataSize);
 
extern bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize);
extern bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize);

Base64Transcoder.c

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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/*
 *  Base64Transcoder.c
 *  Base64Test
 *
 *  Created by Jonathan Wight on Tue Mar 18 2003.
 *  Copyright (c) 2003 Toxic Software. All rights reserved.
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 *
 */
 
#include "Base64Transcoder.h"
 
#include <math.h>
#include <string.h>
 
const u_int8_t kBase64EncodeTable[64] = {
	/*  0 */ 'A',	/*  1 */ 'B',	/*  2 */ 'C',	/*  3 */ 'D', 
	/*  4 */ 'E',	/*  5 */ 'F',	/*  6 */ 'G',	/*  7 */ 'H', 
	/*  8 */ 'I',	/*  9 */ 'J',	/* 10 */ 'K',	/* 11 */ 'L', 
	/* 12 */ 'M',	/* 13 */ 'N',	/* 14 */ 'O',	/* 15 */ 'P', 
	/* 16 */ 'Q',	/* 17 */ 'R',	/* 18 */ 'S',	/* 19 */ 'T', 
	/* 20 */ 'U',	/* 21 */ 'V',	/* 22 */ 'W',	/* 23 */ 'X', 
	/* 24 */ 'Y',	/* 25 */ 'Z',	/* 26 */ 'a',	/* 27 */ 'b', 
	/* 28 */ 'c',	/* 29 */ 'd',	/* 30 */ 'e',	/* 31 */ 'f', 
	/* 32 */ 'g',	/* 33 */ 'h',	/* 34 */ 'i',	/* 35 */ 'j', 
	/* 36 */ 'k',	/* 37 */ 'l',	/* 38 */ 'm',	/* 39 */ 'n', 
	/* 40 */ 'o',	/* 41 */ 'p',	/* 42 */ 'q',	/* 43 */ 'r', 
	/* 44 */ 's',	/* 45 */ 't',	/* 46 */ 'u',	/* 47 */ 'v', 
	/* 48 */ 'w',	/* 49 */ 'x',	/* 50 */ 'y',	/* 51 */ 'z', 
	/* 52 */ '0',	/* 53 */ '1',	/* 54 */ '2',	/* 55 */ '3', 
	/* 56 */ '4',	/* 57 */ '5',	/* 58 */ '6',	/* 59 */ '7', 
	/* 60 */ '8',	/* 61 */ '9',	/* 62 */ '+',	/* 63 */ '/'
};
 
/*
 -1 = Base64 end of data marker.
 -2 = White space (tabs, cr, lf, space)
 -3 = Noise (all non whitespace, non-base64 characters) 
 -4 = Dangerous noise
 -5 = Illegal noise (null byte)
 */
 
const int8_t kBase64DecodeTable[128] = {
	/* 0x00 */ -5, 	/* 0x01 */ -3, 	/* 0x02 */ -3, 	/* 0x03 */ -3,
	/* 0x04 */ -3, 	/* 0x05 */ -3, 	/* 0x06 */ -3, 	/* 0x07 */ -3,
	/* 0x08 */ -3, 	/* 0x09 */ -2, 	/* 0x0a */ -2, 	/* 0x0b */ -2,
	/* 0x0c */ -2, 	/* 0x0d */ -2, 	/* 0x0e */ -3, 	/* 0x0f */ -3,
	/* 0x10 */ -3, 	/* 0x11 */ -3, 	/* 0x12 */ -3, 	/* 0x13 */ -3,
	/* 0x14 */ -3, 	/* 0x15 */ -3, 	/* 0x16 */ -3, 	/* 0x17 */ -3,
	/* 0x18 */ -3, 	/* 0x19 */ -3, 	/* 0x1a */ -3, 	/* 0x1b */ -3,
	/* 0x1c */ -3, 	/* 0x1d */ -3, 	/* 0x1e */ -3, 	/* 0x1f */ -3,
	/* ' ' */ -2,	/* '!' */ -3,	/* '"' */ -3,	/* '#' */ -3,
	/* '$' */ -3,	/* '%' */ -3,	/* '&' */ -3,	/* ''' */ -3,
	/* '(' */ -3,	/* ')' */ -3,	/* '*' */ -3,	/* '+' */ 62,
	/* ',' */ -3,	/* '-' */ -3,	/* '.' */ -3,	/* '/' */ 63,
	/* '0' */ 52,	/* '1' */ 53,	/* '2' */ 54,	/* '3' */ 55,
	/* '4' */ 56,	/* '5' */ 57,	/* '6' */ 58,	/* '7' */ 59,
	/* '8' */ 60,	/* '9' */ 61,	/* ':' */ -3,	/* ';' */ -3,
	/* '<' */ -3,	/* '=' */ -1,	/* '>' */ -3,	/* '?' */ -3,
	/* '@' */ -3,	/* 'A' */ 0,	/* 'B' */  1,	/* 'C' */  2,
	/* 'D' */  3,	/* 'E' */  4,	/* 'F' */  5,	/* 'G' */  6,
	/* 'H' */  7,	/* 'I' */  8,	/* 'J' */  9,	/* 'K' */ 10,
	/* 'L' */ 11,	/* 'M' */ 12,	/* 'N' */ 13,	/* 'O' */ 14,
	/* 'P' */ 15,	/* 'Q' */ 16,	/* 'R' */ 17,	/* 'S' */ 18,
	/* 'T' */ 19,	/* 'U' */ 20,	/* 'V' */ 21,	/* 'W' */ 22,
	/* 'X' */ 23,	/* 'Y' */ 24,	/* 'Z' */ 25,	/* '[' */ -3,
	/* '\' */ -3,	/* ']' */ -3,	/* '^' */ -3,	/* '_' */ -3,
	/* '`' */ -3,	/* 'a' */ 26,	/* 'b' */ 27,	/* 'c' */ 28,
	/* 'd' */ 29,	/* 'e' */ 30,	/* 'f' */ 31,	/* 'g' */ 32,
	/* 'h' */ 33,	/* 'i' */ 34,	/* 'j' */ 35,	/* 'k' */ 36,
	/* 'l' */ 37,	/* 'm' */ 38,	/* 'n' */ 39,	/* 'o' */ 40,
	/* 'p' */ 41,	/* 'q' */ 42,	/* 'r' */ 43,	/* 's' */ 44,
	/* 't' */ 45,	/* 'u' */ 46,	/* 'v' */ 47,	/* 'w' */ 48,
	/* 'x' */ 49,	/* 'y' */ 50,	/* 'z' */ 51,	/* '{' */ -3,
	/* '|' */ -3,	/* '}' */ -3,	/* '~' */ -3,	/* 0x7f */ -3
};
 
const u_int8_t kBits_00000011 = 0x03;
const u_int8_t kBits_00001111 = 0x0F;
const u_int8_t kBits_00110000 = 0x30;
const u_int8_t kBits_00111100 = 0x3C;
const u_int8_t kBits_00111111 = 0x3F;
const u_int8_t kBits_11000000 = 0xC0;
const u_int8_t kBits_11110000 = 0xF0;
const u_int8_t kBits_11111100 = 0xFC;
 
size_t EstimateBas64EncodedDataSize(size_t inDataSize)
{
    size_t theEncodedDataSize = (int)ceil(inDataSize / 3.0) * 4;
    theEncodedDataSize = theEncodedDataSize / 72 * 74 + theEncodedDataSize % 72;
    return(theEncodedDataSize);
}
 
size_t EstimateBas64DecodedDataSize(size_t inDataSize)
{
    size_t theDecodedDataSize = (int)ceil(inDataSize / 4.0) * 3;
    //theDecodedDataSize = theDecodedDataSize / 72 * 74 + theDecodedDataSize % 72;
    return(theDecodedDataSize);
}
 
bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize)
{
    size_t theEncodedDataSize = EstimateBas64EncodedDataSize(inInputDataSize);
    if (*ioOutputDataSize < theEncodedDataSize)
        return(false);
    *ioOutputDataSize = theEncodedDataSize;
    const u_int8_t *theInPtr = (const u_int8_t *)inInputData;
    u_int32_t theInIndex = 0, theOutIndex = 0;
    for (; theInIndex < (inInputDataSize / 3) * 3; theInIndex += 3)
	{
        outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2];
        outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4];
        outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (theInPtr[theInIndex + 2] & kBits_11000000) >> 6];
        outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 2] & kBits_00111111) >> 0];
        if (theOutIndex % 74 == 72)
		{
            outOutputData[theOutIndex++] = '\r';
            outOutputData[theOutIndex++] = '\n';
		}
	}
    const size_t theRemainingBytes = inInputDataSize - theInIndex;
    if (theRemainingBytes == 1)
	{
        outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2];
        outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (0 & kBits_11110000) >> 4];
        outOutputData[theOutIndex++] = '=';
        outOutputData[theOutIndex++] = '=';
        if (theOutIndex % 74 == 72)
		{
            outOutputData[theOutIndex++] = '\r';
            outOutputData[theOutIndex++] = '\n';
		}
	}
    else if (theRemainingBytes == 2)
	{
        outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2];
        outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4];
        outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (0 & kBits_11000000) >> 6];
        outOutputData[theOutIndex++] = '=';
        if (theOutIndex % 74 == 72)
		{
            outOutputData[theOutIndex++] = '\r';
            outOutputData[theOutIndex++] = '\n';
		}
	}
    return(true);
}
 
bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize)
{
    memset(ioOutputData, '.', *ioOutputDataSize);
 
    size_t theDecodedDataSize = EstimateBas64DecodedDataSize(inInputDataSize);
    if (*ioOutputDataSize < theDecodedDataSize)
        return(false);
    *ioOutputDataSize = 0;
    const u_int8_t *theInPtr = (const u_int8_t *)inInputData;
    u_int8_t *theOutPtr = (u_int8_t *)ioOutputData;
    size_t theInIndex = 0, theOutIndex = 0;
    u_int8_t theOutputOctet;
    size_t theSequence = 0;
    for (; theInIndex < inInputDataSize; )
	{
        int8_t theSextet = 0;
 
        int8_t theCurrentInputOctet = theInPtr[theInIndex];
        theSextet = kBase64DecodeTable[theCurrentInputOctet];
        if (theSextet == -1)
            break;
        while (theSextet == -2)
		{
            theCurrentInputOctet = theInPtr[++theInIndex];
            theSextet = kBase64DecodeTable[theCurrentInputOctet];
		}
        while (theSextet == -3)
		{
            theCurrentInputOctet = theInPtr[++theInIndex];
            theSextet = kBase64DecodeTable[theCurrentInputOctet];
		}
        if (theSequence == 0)
		{
            theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 2 & kBits_11111100;
		}
        else if (theSequence == 1)
		{
            theOutputOctet |= (theSextet >- 0 ? theSextet : 0) >> 4 & kBits_00000011;
            theOutPtr[theOutIndex++] = theOutputOctet;
		}
        else if (theSequence == 2)
		{
            theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 4 & kBits_11110000;
		}
        else if (theSequence == 3)
		{
            theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 2 & kBits_00001111;
            theOutPtr[theOutIndex++] = theOutputOctet;
		}
        else if (theSequence == 4)
		{
            theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 6 & kBits_11000000;
		}
        else if (theSequence == 5)
		{
            theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 0 & kBits_00111111;
            theOutPtr[theOutIndex++] = theOutputOctet;
		}
        theSequence = (theSequence + 1) % 6;
        if (theSequence != 2 && theSequence != 4)
            theInIndex++;
	}
    *ioOutputDataSize = theOutIndex;
    return(true);
}

OAUTHnesia.h

#import 
 
@interface OAUTHnesia : NSObject {
@protected
    NSString *CONSUMER_KEY;
    NSString *CONSUMER_SECRET;
    NSString *API_BASE_URL;
}
 
@property(nonatomic, retain) NSString *CONSUMER_KEY;
@property(nonatomic, retain) NSString *CONSUMER_SECRET;
@property(nonatomic, retain) NSString *USER_KEY;
@property(nonatomic, retain) NSString *USER_SECRET;
@property(nonatomic, retain) NSString *API_BASE_URL;
@property(nonatomic, retain) NSString *POST_URL;
@property(nonatomic, retain) NSString *POST_DATA;
 
- (id)initWithKey:(NSString *)cons_key secret:(NSString *)cons_secret;
- (void) setUserKey: (NSString *)user_key;
- (void) setUserSecret: (NSString *)user_secret;
- (NSString *) encodeForOauth: (NSString *) postget;
- (NSString *) getNonce;
- (NSString *) getTime;
- (NSString *) generateBaseSignature: (NSString *) base_sig uri:(NSString *) uri;
- (NSString *) hmacsha1: (NSString *)text key:(NSString *)secret;
- (NSString *) md5: (NSString *)text;
- (NSString *) urlencode: (NSString *)text;
 
- (void) oAuth:(NSString *)oUri oPost:(NSString *)oPost oGet:(NSString *)oGet;
 
@end

OAUTHnesia.m

#import "OAUTHnesia.h"
//
//  OAUTHnesia.m
//  Jajan
//
//  Created by Batista Harahap on 8/14/11.
//  Copyright 2011 Urbanesia.com. All rights reserved.
//
 
#import "OAUTHnesia.h"
#include "Base64Transcoder.h"
#import <CommonCrypto/CommonHMAC.h>
#import <CommonCrypto/CommonDigest.h>
 
@implementation OAUTHnesia
@synthesize CONSUMER_KEY, CONSUMER_SECRET, USER_KEY, USER_SECRET, API_BASE_URL, POST_URL, POST_DATA;
 
- (id)initWithKey:(NSString *)cons_key secret:(NSString *)cons_secret {
    if (self = [super init]) {
        self.CONSUMER_KEY = cons_key;
        self.CONSUMER_SECRET = cons_secret;
        self.API_BASE_URL = @"http://api1.urbanesia.com/";
        self.POST_URL = self.POST_DATA = @"";
    }
 
    return self;
}
 
- (void)oAuth:(NSString *)oUri oPost:(NSString *)oPost oGet:(NSString *)oGet {
    // Post yang pasti harus ada!
    NSString *postIncludes = [NSString stringWithFormat:
        @"oauth_consumer_key=%@&oauth_nonce=%@&oauth_signature_method=HMAC-SHA1&oauth_timestamp=%@&oauth_token=%@&oauth_version=1.0",
        self.CONSUMER_KEY, self.getNonce, self.getTime, self.USER_KEY];
 
    // Cek ada POST ga di request?
    if([oPost isEqual:@""]) {
        oPost = postIncludes;
    } else {
        oPost = [NSString stringWithFormat:@"%@&%@", oPost, postIncludes];
    }
 
    // Cek ada GET ga di request?
    if(![oGet isEqual:@""]) {
        oGet = [NSString stringWithFormat:@"&%@", oGet];
    }
 
    // Encode for OAUTH & Generate Base Signature
    NSString *base_sig = [self generateBaseSignature:[self encodeForOauth:[NSString stringWithFormat:@"%@%@", oPost, oGet]] uri:oUri];
 
    // OAUTH Signature
    NSString *signature = [self hmacsha1:[NSString stringWithFormat:@"%@&%@", self.CONSUMER_SECRET, self.USER_SECRET] key:base_sig];
 
    // POST URL
    self.POST_URL = [NSString stringWithFormat:@"%@%@?oauth_signature=%@%@", self.API_BASE_URL, oUri, signature, oGet];
 
    // POST DATA
    self.POST_DATA = oPost;
}
 
- (void)setUserKey:(NSString *)user_key {
    self.USER_KEY = user_key;
}
 
- (void)setUserSecret:(NSString *)user_secret {
    self.USER_SECRET = user_secret;
}
 
- (NSString *)getNonce {
    NSTimeInterval timePassed_ms = [[NSDate date] timeIntervalSinceNow] * -1000.0;
    return [self md5:[NSString stringWithFormat:@"%@", timePassed_ms]];
}
 
- (NSString *)getTime {
    NSTimeInterval timePassed_ms = [[NSDate date] timeIntervalSinceNow] * -1000.0;
    return [NSString stringWithFormat:@"%@", timePassed_ms];
}
 
- (NSString *)generateBaseSignature:(NSString *)base_sig uri:(NSString *)uri {
    NSString *dest = [NSString stringWithFormat:@"%@%@", self.API_BASE_URL, uri];
    dest = [self urlencode:dest];
    base_sig = [self urlencode:base_sig];
    return [NSString stringWithFormat:@"POST&%@&%@", dest, base_sig];
}
 
- (NSString *)encodeForOauth: (NSString *)postget {
    // Explode to array
    NSArray *par = [postget componentsSeparatedByString:@"&"];
 
    // Sort by array keys
    par = [par sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
 
    NSString *ret = @"";
 
    for(int i=0, j=0, max=par.count; i<max; i++) {
        if(j==1)
            ret = [NSString stringWithFormat:@"%@&", ret];
 
        NSArray *temp = [[par objectAtIndex:i] componentsSeparatedByString:@"="];
        NSString *k = (NSString *)[temp objectAtIndex:0];
        k = [self urlencode:k];
        NSString *v = (NSString *)[temp objectAtIndex:1];
        v = [self urlencode:v];
        ret = [NSString stringWithFormat:@"%@%@=%@", ret, k, v];
 
        j = 1;
    }
 
    return ret;
}
 
- (NSString *)urlencode:(NSString *)text {
    return [text stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
}
 
- (NSString *)md5:(NSString *)text {
    const char* str = [text UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(str, strlen(str), result);
    NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
    for(int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {
        [ret appendFormat:@"%02x",result[i]];
    }
    return ret;
}
 
- (NSString *)hmacsha1:(NSString *)text key:(NSString *)secret {
    NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding];
    NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding];
    unsigned char result[20];
	CCHmac(kCCHmacAlgSHA1, [secretData bytes], [secretData length], [clearTextData bytes], [clearTextData length], result);
 
    char base64Result[32];
    size_t theResultLength = 32;
    Base64EncodeData(result, 20, base64Result, &theResultLength);
    NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength];
 
    NSString *base64EncodedResult = [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding];
 
    return base64EncodedResult;
}
 
@end

photo of Batista Batista R Harahap [email protected]
Jl. Bango II/29C, Pondok Labu
Cilandak , DKI Jakarta , 12450 Indonesia
62817847023

This hCard created with the hCard creator.