Sunday, 26 February 2012

Tutorial - How to setup MathJax locally

[Update 02/03/2012] Please also have a look at this post - Tutorial - How to setup MathJax locally - "slim" edition

In this post last year, I talked about how to get MathJax working in your iPhone project. However that requires internet connection as the JavaScript in MathJax needs to connect back to their web site to get all the fonts and details, otherwise all those math formulas won't be displayed properly.

In this post I am going to talk about how I setup my iPhone/iPad project to use MathJax "locally" so that your math formulas can be displayed properly even if there's no Internet connection.

Before you start

A few things you have to be aware of:
1) Nothing is free, to provide this convenience, you have to add the 25+MB MathJax library into your Xcode project
2) As your final application will be over the 20MB limit, your users/customers won't be able to download it directly from the iPhone/iPad device, they have to connect it to a PC/Mac to down your application and future updates.
3) From my observation, I noticed when the JavaScript runs, it still tries to connect to their web site, and then it fall back to use the local copy (as shown in screen dumps below: 1st one says "Loading Web-Font TeX/Main/Regular", 2nd one says "Web-Fonts not available -- using image fonts instead").

If this is not what you expected, and you still want to use MathJax in your application, may be you should just follow the example in the previous MathJax post.

How was it done?

At a high level - using the same technique mentioned in the MathJax post last year, we will first write a HTML file locally and then display it using UIWebView. But the difference this time, is we will change the reference to the JavaScript to point to local directory, so it can fall back locally if internet connection is not available for whatever reason.

What's this JavaScript about?

If you look at any examples from the MathJax web site (for example: this one, or this one) and view source, you will see this link somewhere in the page.

<script type="text/javascript" src=""></script>

This JavaScript is the main component that makes the whole thing works. Our task is to change the link for it to point to the local copy of MathJax library, that is, change the part highlighted in red.

Steps Involved

1. Start a new project with single view, I am using the name "MathJaxLocal".

2. Download MathJax from this link, under "Downloads for Local Installation" section, select the link which at this time of writing, says "Current Version: (15.4MB)".

3. Expand the downloaded .ZIP file, to make it easier to differentiate between different version, I renamed the folder name to "mathjax-MathJax-v1.1a".

4. Drag and drop the whole "mathjax-MathJax-v1.1a" folder into your Xcode project. At the popup screen as shown below, make sure you click "Copy Items into destination group's folder (if needed)" and  "Create folder reference for any added folders". Otherwise the folder structure won't be created properly.

Please note that it's quite big and might take a few minutes depending on how powerful your machine is, so please be patient.

5. Once it's done, you should see as below a special blue coloured folder with all the MathJax files copied into your project. Feel free to expand it and explore around.

6. Now let's start changing the code, first add a UIWebView declaration. If you are lazy like me, just stick it somewhere in the beginning of your UIViewController file.

UIWebView *myWebView;

7. Next, let's add a new method, which will handle writing HTML file locally, I called it "writeStringToFile". It basically concatenates a few strings into a big one and then write to the specified path with specified filename.

-(void)writeStringToFile:(NSString *)dir fileName:(NSString *)strFileName pathName:(NSString *)strPath content:(NSString *)strContent{
    NSLog(@" inside writeStringToFile, strPath=%@", strPath);
    NSString *path = [dir stringByAppendingPathComponent:strFileName];
    NSString *foo0 = @"<html><head><meta name='viewport' content='initial-scale=1.0' />"
"<script type='text/javascript' src='";
    NSString *foo1 = @"?config=TeX-AMS-MML_HTMLorMML-full'></script>"
    NSString *foo2 = @"</body></html>";
    NSString *fooFinal = [NSString stringWithFormat:@"%@%@%@%@%@",foo0,strPath,foo1,strContent,foo2];
    NSLog(@"Final content is %@",fooFinal);
    [fooFinal writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];


8.  Finally add the following code into your "viewDidLoad" or whichever method which you think appropriate. Note that I copied 2 examples from their web site, you can change it to see the differences. 1st one is for "TEX" and there's more work as you have to change all the single slash "\" to double slashes "\\", the 2nd one is for "MathML"

     //content copied from
     NSString *xContent = @"<p>\\["
     "\\left( \\sum_{k=1}^n a_k b_k \\right)^{\\!\\!2} \\leq"
     "\\left( \\sum_{k=1}^n a_k^2 \\right) \\left( \\sum_{k=1}^n b_k^2 \\right)"
     "\\frac{1}{(\\sqrt{\\phi \\sqrt{5}}-\\phi) e^{\\frac25 \\pi}} ="
     "1+\\frac{e^{-2\\pi}} {1+\\frac{e^{-4\\pi}} {1+\\frac{e^{-6\\pi}}"
     "|{1+\\frac{e^{-8\\pi}} {1+\\ldots} } } }"
    NSString *xContent =@"When <math><mi>a</mi><mo>&#x2260;</mo><mn>0</mn></math>,"
    "there are two solutions to <math>"
    "<mo>+</mo> <mi>b</mi><mi>x</mi>"
    "<mo>+</mo> <mi>c</mi> <mo>=</mo> <mn>0</mn>"
    "</math> and they are"
    "<math mode='display'>"
    "<mi>x</mi> <mo>=</mo>"
    "<mrow> <mn>2</mn><mi>a</mi> </mrow>"
    //temp file filename
    NSString *tmpFileName = @"test1.html";
    //temp dir
    NSString *tempDir = NSTemporaryDirectory();
    NSLog(@"tempDirectory: %@",tempDir);
    //create NSURL
    NSString *path4 = [tempDir stringByAppendingPathComponent:tmpFileName];
    NSURL* url = [NSURL fileURLWithPath:path4]; 
    NSLog(@"Path=%@, url=%@",path4,url);
    //setup HTML file contents
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"MathJax" ofType:@"js" inDirectory:@"mathjax-MathJax-v1.1a"];
    NSLog(@"filePath = %@",filePath);
    //write to temp file "tempDir/tmpFileName", set MathJax JavaScript to use "filePath" as directory, add "xContent" as content of HTML file
    [self writeStringToFile:tempDir fileName:tmpFileName pathName:filePath content:xContent];
    //create UIWebView
    CGRect webRect = CGRectMake(10,10,300,400);
    myWebView =[[UIWebView alloc] initWithFrame:webRect];
    myWebView.scalesPageToFit = YES;
    myWebView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
//[Update 21/03/2013] This step no longer required
// myWebView.delegate = self;
    NSURLRequest* req = [[NSURLRequest alloc] initWithURL:url]; 
    //original request to show MathJax stuffs
    [myWebView loadRequest:req];
    [self.view addSubview:myWebView];
    [req release];

You can now run your application, again it might take a while for 1st run due to the huge file size. The result of 1st example is shown below:

For 2nd example using "MathML", the result is as below:

[Update 21/03/2013] This step no longer required
I noticed there's this warning as shown below saying "Assigning to 'id' from incompatible type 'ViewController *'", which I don't know why as I have seen other examples on the net also doing the same thing - assigning UIWebView.delegate to "self". Let me know if any of you have any idea about this or how to get rid of it.

myWebView.delegate = self;

That's it, hope you find this helpful. And as usual, let me know if you need further information or have any better idea about this. Thanks!

[Update 21/03/2013] This step no longer required
[Update 02/03/2012] I found the fix to get rid of the warning. Just need to change this line in "ViewController.h" header file

@interface ViewController : UIViewController

to this

@interface ViewController : UIViewController <UIWebViewDelegate>

[Update 21/03/2013]
I tried MathJax v2.1 on Xcode 4.6 and following the steps in this post, got it working on iPhone/iPad 6.1 simulator and on my iPhone 5 as well. Please see this post for other further info.

Saturday, 18 February 2012

Oh, I didn't know that there are 2 iPhone simulators in Xcode?

I think most of you might already know this. It's a bit embarrassing, but I have to admit that I just found out about this a few days ago by accident...

If you have been following my blog you might have noticed all my screen dumps were like the one below, using the iPhone simulator in Xcode - which surely looks like a nice iPhone 4 device.

I then found that by clicking on the "Hardware -> Device" option in "iOS simulator", as shown below, there's a "iPhone (Retina)" one which I never seen before... Now, where did that come from??!!

And then it switched to an ugly, rectangular shape, urh........... "box"? What, you call that an iPhone with Retina display? Are you sure this is made by Apple? This looks more like the iPad simulator to be honest, but the header says "iPhone (Retina)"...
If you look at the log below, the "screenBound.size" is still 480x320 which is the same as above. But "screenScale" is now 2.0 instead of the 1.0 shown in previous screen... So may be this ugly thing is indeed the iPhone simulator with Retina display.... Now we have one extra "device" to test on for all future projects....damn...

And probably because the "screenScale" remains the same, when I use the following methods to fill the background colour using same pattern (but with another transparent view to slightly change the colour), as shown far below, it looks the same on both.

    [UIColor colorWithPatternImage: [UIImage imageNamed:imageFileName]]

Recently, we have all seen lots of "rumours" about Apple going to release iPad 3 with Retina display sometime in the next few months. I would surely check to see if there's going to be a new "iPad (Retina)" option when the next version of Xcode been released (mine currently 4.2)...

[Update 09/03/2012] see this post for info about the iPad retina (iPad 3) simulator in new Xcode 4.3.1

Tuesday, 14 February 2012

Universal project is the way to go?

As you might be aware, Apple sold more iPad in last 3 months of 2011 than HP (see reports here and here as example), this sort of pushed me to not only targeting iPhone, but also more into Universal projects - targeting both iPhone and iPad.

As I still don't quite like NIB files, so although Xcode automatically creates 2 separate NIB files I still like to "parameterise" the display section, and setup different parameters accordingly depending on the platform it's running on.

I also moved back to the non-Cocos2D world, trying to refresh my memory and make myself more familiarise with the non-Cocos2D way of doing things. So far so good, hopefully can get something working very soon.

Unfortunately got stuck on something today - was trying to use Nextpeer to add "multi-player" function - however, found it doesn't work with iPad that well (as shown below) and confirmed with Daniel/Nextpeer that iPad support is still not ready yet. So looks like have to put multi-player part for iPad version on hold for a while.

Thursday, 9 February 2012

Someone copied my game!

Last September, I wrote in this post about someone who copied the "ABC123" open source game, changed the background colour plus a few minor stuffs, and then publish the whole game as his. Today, I found it happened to me too!!!

I first noticed this "Dice in Cup" game a few days ago, as below, it's published on 21st Dec 2011.
I played with it for a while and noticed strong similarity with my "Dice in Cup" open source game published on 15th November 2011. If you look at the screen dump below and compare with the video I posted in this post, you will notice other than the image difference, the font, the label, the location of the label, even the points you gain after passing each level is exactly the same!
Even the name of app after installed, the one to the left is his, the one to the right is mine, is exactly the same! There's a few "..." in the middle because I called my game a very long name: "Cocos2dDiceInCup":

To further clarify, I use the method I mentioned in this post to inspect the ".ipa" file after sync with a Windows machine. As shown below, the name is indeed "Cocos2dDiceInCup"!
After renamed it to ".zip" and expanded, the content is shown below, although he did add quite a few image/music/sound files, he didn't even delete my 2 old image files: "rockImage.png" and "seeker.png"!
As shown below from my published source, those 2 image files are there.

Ok, so based on my investigation, this guy copied my whole game, added some sound and music, added a background image, changed the cup/dice image and added a starting page.

[Update 10/02/2012] After some further study, looks like I have to admit I didn't have enough understanding of Open Source at the beginning.

My main purpose of sharing was simply to help others to learn - like so many others who have helped me in the past. And I naively thought that everyone will have similar thinking - to appreciate others' generosity, to respect others' intellectual property, and also somehow contribute back to the community to make it even better.

Unfortunately, there's always some people who would simply tastelessly copy everything and then publish it without giving any credit to the original creator. This really hurts my feeling, and I will certainly think twice before publishing anything... Sad... :-(

[Update 11/04/2012] This issue has been on my mind for a while. After calmed down a bit, I think it's me who is the silly one - who didn't fully understand the meaning of Open Source at the beginning, then probably felt hurt as others published something before me using my code (I still haven't publish anything yet :-( ...), thus came up with all these negative stuffs.

But hey, that's Open Source! You suppose to feel proud that someone did copy your stuff as that would be some sort of "recognition"!

My apology if my negative feeling caused any confusion or hurt any one. Was thinking of deleting this/previous post, but on second thought, decide to leave it as a reminder - to show what sort of dumb mistake I have made - released code as Open Source and then criticise others for copying it.... Silly me...

Friday, 3 February 2012

A few more things about Nextpeer

Spent quite some time on Nextpeer in past 2 weeks, and also created quite a few posts about it recently.

Planning to move on to other topics soon, so would like to summarise a few more things as below. Will definitely talk about it again if there's any new interesting development in this area.

Coins handling

Still not very clear about coins handling. Like to have clear flow from developer's point of view, from users' point of view. What's the selling/attracting point for each party?, why would users want to buy more coins if you can get it free by playing as guest? are they redeemable? is it fair?...etc need clear answers to all sorts of what if questions.

Nextpeer is definitely an interesting product. Although still in early stage, can see some potential in there.

The huge scrolling result list

If you ever visit Nextpeer home page, you definitely won't miss the huge scrolling result list - keep updating with the latest results every few seconds. And if you clicked on any of them, it will redirect you to the iTunes page for you to download the game, not bad!

To be honest, I always thought it isn't real. As based on my observation, Nextpeer "sometimes" use simulated players to give you the multi-player "user experience".

Until today...

I was playing around with Nextpeer using my "non-Cocos2d" game Follow me if you can. While working on it, I accidentally toggled to the Nextpeer home page and found the result displayed on it - as shown below. I didn't change the default Tournament Title, that's why it's shown like that.

Tried another tournament, purposely get 0 points. As shown below, the "simulated" 1st prize winner also added to the list, cool!

Unfortunately, my simple game still not published to App Store yet, so when I clicked on it, just get a blank page. Damn!

Ok, I was a bit too excited. Technically, the SDK pass data back to the server after the game ends any more, so there shouldn't be anything exciting about displaying result on the web page.

Again it's the "user experience" - the fact that my game can get some exposure on their home page when someone plays it sort of excited me a bit. As for how many people will be staring at that result list like me during that moment is a different issue...

Stuck with SDK for non-Cocos2D game

I found a few problems with integrating the SDK to my non-COcos2D game and got stuck. One problem is, when I started a new tournament, found that the game still shows the last screen of the previous tournament and the score wasn't reset... Must have missed something somewhere. Will wait for the updated tutorial then...

Not suitable for games with multiple sub-games?

While still waiting for more info about how to handle multiple tournaments, I think with the current design, it's probably not suitable for games which has multiple sub-games. I mean like the extreme example of this 101-in-1 Games I mentioned before. It would be really challenging to work out a solution for that kind of games.

How to co-exist with Game Center and other tools?

I was also thinking, is it suitable to have Nextpeer and Game Center (or OpenFeint and other products) integrated to the same game? Would be very helpful if Nextpeer can provide some analysis on that and provide some recommendation.

Response from Shai/Nextpeer

Thanks to Shai/Nextpeer who answered a few questions I raised before, please see below.


Regarding your further questions in the post:

2) Like to see example of setting up Netxpeer with non-Cocos2D projects
- We will upload a new video and tutorial next week about how to integrate a simple Objective-C game.

3) How is the gold coins been handled? 
What if I run out of coins, how do I get more? 
Is that through in-app purchase or some other methods?
How is the profit distributed between Nextpeer and the developer?
  • The gold coins are separated for each game (as same as the level for each game)
  • Currently, if you ran out of coins you'll automatically get a small amount for free. (You need to close the app and come back to do that)
  • In a few weeks we plan to launch an SDK with iAP for coins. We will enable developers sell iAP and do rev-share with us. 
  • The rev-share info is usually 50-50.
  • Using the coins your users will be able to buy an avatar and other things to their friends.
  • Also, in the near future we'll provide developers the ability to sell virtual goods or "power ups" for multiplayer mode using Nextpeer coins.

Please check the Stanford event next week on Tuesday:
- Mobile Gaming Class @ Stanford GSB: Make a Multiplayer iOS Game in 75 Minutes
It would be great if you can share it with other friends/people.

Thanks for your posts. It really helps us. 


~ Shai