Tuesday, April 20, 2010

Progress with Android 1.5

Recently in Ansca's Corona Lab we decided to support Android 1.5. As of today, the Corona 2.0 beta supports Android 2.0.1. We have several requests to support earlier versions from our Japan group and several customers. And as you can see from the following data, there's a lot of older phones out there:


(Source: Google)

After experimenting a bit, it looks like porting to Android 1.5 isn't too hard. There are a few missing APIs compared to the newer SDK, but for the most part that's ok. Here's a screenshot of Core Damage running in the Android 1.5 emulator:



Sound is working as well. Internally it looks like there's some missing OpenGL functionality as well, so I'll have to do some exploring to see what that means for the Corona rendering engine. Also, I don't have a device to test it on, although someone in the office has a 1.6 phone. I'm sure we can solve that problem.

Nonetheless, this is an exciting development, as it opens Corona's horizons much wider! We should be able to get this into an upcoming Corona beta update in the next couple weeks.

Friday, April 16, 2010

Objective-C to Lua translator

Supposing, of course, that speculation is correct and iPhone developers will be prohibited from originating their apps using any language other than C, C++, and Objective-C, it's only natural that one should translate those languages to the language of one's choice. I've spent a few hours trying to do just that. Naturally, I used Lua's excellent LPEG library, and googled for bits of Objective-C grammar.

Here's the input to the translator:

// This is a comment
#import "foobar"

int i = 1;

-(void)mySelector:(int)count
{
    int foo = 3;
    int bar;
}

The results of the translation are:

-- This is a comment
 require "foobar"
 local i = 1; function mySelector(count) local foo = 3; local bar; end 


The Lua code is:

require 're'

parser = re.compile[[
 S <- <externaldeclaration>*
 WS <- [ %nl\t]+
 NWS <- [ %nl\t]*
 IDENTIFIER <- ([%a$_] [%a$_%d]*)
 LINECOMMENT <- '//' {[^%nl]* %nl} -> '--%1'
 COMMENT <- '/*' <CLOSECOMMENT> -> '--'
 COMMENTMIDDLE <- {.} <CLOSECOMMENT> -> '%1'
 CLOSECOMMENT <- '*/' / <COMMENTMIDDLE>
 IMPORT <- ('#import' <WS> <filespecification>) / ('#include' <WS> <filespecification>)
 filespecification <- (["<] {[%a%d%s/_]+} [">]{%nl}) -> 'require "%1"%2'
 preprocessordeclaration <- <IMPORT> 
 identifier <- <IDENTIFIER>
 DECIMALLITERAL <- {%d+} <IntegerTypeSuffix>? -> '%1'
 IntegerTypeSuffix <- [uUlL]
 STRINGLITERAL <- { ('"' ( <EscapeSequence> / [^\"] )* '%') } -> '%1'
 EscapeSequence <- '\' [btnfr"'\] / <OctalEscape>
 OctalEscape <- ('\' [0-3] [0-7] [0-7]) / ('\' [0-7] [0-7]) / ('%' [0-7])
 constant <- <DECIMALLITERAL>

 externaldeclaration <-
  <WS>
  / <COMMENT> 
  / <LINECOMMENT> 
  / <preprocessordeclaration>
  / <declaration>
  / <instancemethoddefinition>

 typespecifier <- 
  ('void' / 'char' / 'short' / 'int' / 'long' / 'float' / 'double' / 'signed' / 'unsigned' 
  / <identifier>)

 declaration <- ( <declarationspecifiers> <NWS> <initdeclaratorlist>? <NWS> ';' <NWS> )
 declarationspecifiers <- <typespecifier>

 initdeclaratorlist <- <declarator>

 declarator <- <directdeclarator>

 directdeclarator <- {<identifier> <NWS> ( '=' <NWS> <primaryexpression> )? <NWS> } -> "local %1;"

 expression <- (<assignmentexpression> <NWS> (',' <NWS> <assignmentexpression> <NWS> )* )

 assignmentexpression <- <conditionalexpression> ( <NWS> <assignmentoperator> <NWS>  <assignmentexpression>)?

 assignmentoperator <- ('=' / '*=' / '/=' / '%=' / '+=' / '-=' / '<<=' / '>>=' / '&=' / '^=' / '|=') <NWS>

 conditionalexpression <- <logicalorexpression> <NWS> ('?' <NWS> <logicalorexpression> <NWS> ':' <NWS> <logicalorexpression> <NWS>)?

 constantexpression <- <conditionalexpression>

 logicalorexpression <- <logicalandexpression> <NWS> 
   ('||' <NWS> <logicalandexpression> <NWS>)*

 logicalandexpression <- <inclusiveorexpression> <NWS> 
   ('&&' <NWS>  <inclusiveorexpression> <NWS>)*

 inclusiveorexpression <- <exclusiveorexpression> <NWS> 
   ('|' <NWS> <exclusiveorexpression> <NWS>)*

 exclusiveorexpression <- <andexpression> <NWS>  ('^' <NWS>  <andexpression> <NWS>)*

 andexpression <- <equalityexpression> <NWS> ('&' <NWS> <equalityexpression> <NWS>)*

 equalityexpression <- <relationalexpression> <NWS>
   (('!=' / '==') <NWS> <relationalexpression> <NWS>)*

 relationalexpression <- <shiftexpression> <NWS>
  (('<' / '>' / '<=' / '>=') <NWS> <shiftexpression> <NWS>)*

 shiftexpression <- <additiveexpression> <NWS> (('<<' / '>>') <NWS> <additiveexpression> <NWS>)*

 additiveexpression <- <multiplicativeexpression> <NWS> 
   (('+' / '-') <NWS> <multiplicativeexpression> <NWS>)*

 multiplicativeexpression <- <castexpression> <NWS> 
   (('*' / '/' / '%') <NWS> <castexpression> <NWS>)*

 castexpression <- ('(' <NWS> <typename> <NWS> ')' <NWS> <castexpression>) / (<unaryexpression> <NWS>)

 unaryexpression <- <postfixexpression>
   / ('++' <NWS> <unaryexpression> <NWS> )
   / ('--' <NWS> <unaryexpression> <NWS> )
   / (<unaryoperator> <NWS> <castexpression> <NWS> )
   / ('sizeof' <NWS> ( ('(' <NWS> <typename> <NWS> ')') / (<unaryexpression> <NWS>) ) )

 unaryoperator <- ( ( '&' / '*' / '-' / '~' / '!' ) <NWS>)

 postfixexpression <- <primaryexpression>
   ( ('[' <NWS> <expression> <NWS> ']' <NWS>)
   / ('.' <NWS> <identifier> <NWS>)
   / ('->' <NWS> <identifier> <NWS>)
   / ('++' <NWS>)
   / ('--' <NWS>)
   )*

 primaryexpression <-
  ( <IDENTIFIER> <NWS> )
  / ( <constant> <NWS> )
  / ( <STRINGLITERAL> <NWS> )

 instancemethoddefinition <- ('-' <NWS> <methoddefinition> <NWS>)
   
 methoddefinition <- (<methodtype>)? <methodselector> <compoundstatement>
 
 methodselector <- (<keyworddeclarator>+ / <plainselector>)
 plainselector <- {<selector>} <NWS> -> 'function %1()'

 selector <- <IDENTIFIER>

 methodtype <- '(' <NWS> <typename> <NWS> ')' <NWS>

 typename <- (<typespecifier>)
 keyworddeclarator <- ( { <selector> } <NWS> ':' <NWS> <parameter> <NWS> ) -> 'function %1(%2)'

 parameter <- <methodtype> {<IDENTIFIER>}
 
 compoundstatement <- '{' <NWS> (<declaration>)* <NWS> <statementlist>? <NWS> '}' <NWS> -> 'end'

 statementlist <- (<statement>)+ 

 statement <- <WS>
  / ';'
  / (<expression> <NWS> ';')
  / <compoundstatement>
  / <selectionstatement>

 selectionstatement
  <- ('if' <NWS> '(' <NWS> <expression> <NWS> ')' <statement> <NWS> ('else' <NWS> <statement>)? <NWS> )
]]

print(parser:match[[
// This is a comment
#import "foobar"

int i = 1;

-(void)mySelector:(int)count
{
    int foo = 3;
    int bar;
}
]]
)



Saturday, April 10, 2010

The quiet in the middle of a raging category 5 hurricane

It's been a couple of days since the Apple dropped a nuclear bomb into the iPhone developer community . The initial shock has faded, but many questions remain. What will Apple actually do? Will they actively enforce their new restrictions? Will they respond to the serious concerns of the broad development community and modify the language? Or will they simply leave it as a strong No Trespassing warning, with a loaded shotgun on the porch ready to use whenever they wake up from their nap?

Meanwhile, various 3rd party developers critique the policy.

Adobe CTO Kevin Lynch concentrates attention on the CS5 launch, downplays the importance of the Flash packager for iPhone, and looks beyond. Is that capitulation, or merely putting all of the fuss into (much needed) perspective?

Behind the scenes at Adobe, a personal blog by Lee Brimelow underscores the emotional impact of the issue.

3rd party developer Appcelerator's CEO Jeff Haynie waits anxiously for Apple to clarify its position. I don't anticipate Apple doing any such thing anytime soon. They have all the cards, and they've never been one to worry too much about pissing off developers -- remember Hypercard? Cyberdog? Metrowerks? The list goes on and on.

Ansca CTO Walter Luh confidently discusses their position.

CEO Robert Virkus of Enough Software blogs about the clause, arguing that developers should band together to discuss their options, including legal ones if necessary. They don't use the word monopoly, but this is clearly implied: "this lock in effect of clause 3.3.1 is not fair because Apple uses its dominant position in the mobile application space to force developers to develop directly for its platform."

MonoTouch's official statement is here and affirms support for Apple's SDK 4.0, stating "If Apple's motives are technical, or are intended to ensure the use of the Apple toolchain, MonoTouch should have little difficulty staying compliant with the terms of the SDK."

Unity CEO David Helgason weighs in with their position here, noting "the new ToS are difficult to parse with certainty and open to broad interpretation"

Luckily we now have some humorous takes on the situation... Music may now only be produced with GarageBand, and Apple's developer license prohibits apps written by the left hand.

Meanwhile, a few iPhone developers are hanging up their hats. Dan Grigsby at Mobile Orchard is stopping publication and abandoning iPhone development. This is an admirable and principled stance, although I wouldn't expect many iPhone developers to follow suit.

On the iTunes store, Muchosmedia's application Just Letters says "it is probably that [the Just Letters app] will soon be banished from the walled garden of Eden. How tragic." Humorously the app price has now been raised to $199.99. Good luck with that.

The real winner in all of this has to be Android, and by extension, Google. As the mobile OS popularity rivals and potentially exceeds that of the mighty iPhone, if 3rd party developers are locked (or frightened) out of the iPhone world, there is exactly one place they can go, and that is Android. All of that talent and innovation, all of the rapid development frameworks, and all of the non-Objective-C developers out there (and there are a LOT) will look to the increasingly attractive alternative. Any plans that were formerly iPhone-first, port-to-Android-etc-second, suddenly change to Android-ASAP (with a possibility of Palm, Blackberry, etc support later).

Update: Ars Technica weighs in with this review. In it, they state "this move hurts Android. In fact, I think the harm done to Android could end up being even more substantial than the harm to Adobe. Although I would say that the biggest virtues of these banned tools are faster, easier development, the fact is that they also often encourage cross-platform development". I took the opposite position. Yes, it's true that from the vantage point of an iPhone developer, if I have an Objective-C app, I will have a higher hill to climb for Android (than if I could use a porting tool). That is true today. But the 3rd party tools, driven to Android, will in fact make it easier to develop any app for Android. Worst case, you may have to rewrite from scratch for Android, but you won't have to pay nearly the same price as you did for Objective-C. And in fact, many prospective app developers who wouldn't have been able to use Objective-C in the first place, will have no place to go but Android.

Friday, April 9, 2010

Into the firestorm

Yesterday was the day that you didn't want to have anytime soon, if you were in the alternative iPhone app development world.

Apple announced some drastic changes to its SDK, quietly, by publishing a new license on the same day that iPhone OS 4.0 was announced. The twitterverse went bananas after Daring Fireball noticed the change in text.

There are subtle phrases in there that would require a team of lawyers to untangle. What do "originally written", "compile" and "link" mean?

Suppose I write a specification for an app that reads like this:
  • Display background image
  • Display score at bottom left of screen
  • Randomly place 10 bombs on screen
  • When user touches a bomb, remove it and increase score by 10
  • Set 30 second timer. When timer elapses, game is over
I just "wrote" an app in a language called "English". Am I therefore prohibited from making an iPhone version of the game?

What does "compile" mean? Ok, so directly using an interpreter is probably not ok. What if you use a compiler to an intermediate format? For example, let's say you compile C# to C (which then compiles in XCode to ARM). Is that ok because it doesn't directly "compile" against the APIs?

What if the app is written in Objective-C, which is then translated to C#, compiles to Perl, which then is compiled into Lua, which then is cross-compiled into Pascal, which then is compiled to Java bytecode, which is then compiled into C?

How about "link"? Does that mean any language "instruction" that invokes an iPhone API "links" to it? Take the following pseudo-XML:

<circle r=25 x=100 y=50/>

This XML simply tells another piece of code to use native APIs to draw a circle. Does it "link" against the native API? If so, any app that loads XML data could be considered in violation. XML is a "language", and it's not C, Objective-C, or C++. And an XML parser sure looks like an intermediary compatibility layer.

To reiterate, what if I compile most of the app in C first, and the app internally runs a state machine that can do different things based on input? For example, touching the screen paints a circle. Ok, now let's supposed the input isn't from my finger, but is from an XML file that originally was generated by a PHP script on a server?

(Yeah, I know that many XML apps should really be web apps, in general, but XML is commonly used as a format for data exchange on the net, such as retrieving a list of customers from a remote database.)

At what point does a language of any kind become the Application? Is it a 50% binary size kind of thing? What if I have a small piece of code that mostly loads very large images?

What about applications that use SQL? It is a language. Strangely enough, Apple ships sqllite in the iPhone SDK. Does that mean we can't use it?

This is pretty ridiculous. Standard Computer Science says merely that CPUs execute instructions. Those instructions read and modify data. How the instructions are generated, and where the data comes from, are abstract concepts. Apple wants all of the instructions to stay in the Apple box, and they want the data to come from the Apple data pipe as well. That's not good for anyone but Apple.

Developers are like cats. Apple is trying to herd cats here, but has only succeeded in freaking them out.

Interestingly, Windows Phone 7 created the exact same kind of platform lock-in by neglecting to ship a native development kit. That means you can only create apps for that platform in Microsoft's tools. It's a similar situation because things you could do in WinMo 6.5 and before just can't be done in WinPho 7. Unfortunately for MS, they are the also-ran in the smartphone space at this point, so fewer people care. Nonetheless, they managed to royally piss off a lot of developers who have made a large investment in native code on their platforms. Apple's doing the same thing, but in a slightly different direction. MS is saying you can't port to their platform. Apple is saying you can't port away from their platform (at least, not the Objective-C part).

Similarly, Palm originally didn't allow native applications, but more recently shipped a native development kit (which they call a PDK). Maybe Microsoft will relent at some point. They said at one point that they are working with Adobe to port Flash to their browser, so clearly under the hood there's an NDK, just not public yet. Maybe.

By the way, Daring Fireball follows up on the issue makes the strange assertion that "Cross-platform software toolkits have never — ever — produced top-notch native apps for Apple platforms". That is just flat out not true. First of all, most of the entire Adobe Creative Suite is built on cross platform toolkits. Ok, let's stretch reality and say that even though they are popular, they aren't top-notch. There is a laundry list of top iPhone and Mac apps and games that are built with cross-platform tools from Unity.