Showing posts with label ios. Show all posts
Showing posts with label ios. Show all posts

Saturday, November 30, 2019

How to do iOS Receipt Validation in Objective-C

Until you do it yourself, receipt validation might feel like one of the most unclear topic, when it comes to verifying In App Purchases (IAP) on iOS platform for an App Developer.

This post documents the exact steps and code needed to perform receipt validation with AppStore.

The Receipt

As soon as the app is installed or updated, Apple puts a purchase receipt (signed by Apple via AppStore) in the main bundle of the app.

Think of the receipt as the trusted record of a purchase. It also includes any in-app purchases that the user might have made.

Receipt Validation

By verifying the receipts, App Developers can protect their revenue and enforce their business model directly in their application. Receipt Validation plays a key role in verifying whether the auto-renewing subscription is currently active or not.

Here are the steps needed to validate the receipt.
  • First step in the process is to load the receipt from apps main bundle
  • If the receipt is not found, we could refresh the receipt using SKReceiptRefreshRequest
    • This is especially helpful during development and debugging.
  • Refreshing the receipt tells the system that the application needs to retrieve a new receipt

  • Before we could send the receipt information to AppStore, we will need the App's Shared Secret.
  • To get this, log on to itunesconnect and navigate to My Apps -> Click on your App -> Click on Features 
  • Click on the In-App Purchases section. On the right side you will see the link App-Specific Shared Secret, click this link to generate the App-Specific Shared Secret. It will pop up a dialog where you could generate a new secret or view the existing secret.
  • Note down the generate secret somewhere, we need to pass this value to AppStore for receipt verification.

  • Next, we need send the receipt details along with App-Specific Shared Secret to AppStore. We have to hit different URL based on whether the app is running in the sandbox environment or production environment.
  • Now we need to send the Base 64 encoded receipt information along with App-Specific shared secret to the AppStore API. The response of this API is a JSON object with details about various purchases user has made on the app.
  • Full list of receipt fields found in this JSON response can be found here
  • "latest_receipt_info" field is part of the JSON response. It is an Array containing the details of IAP and Subscription purchases made by the user on the app. 
  • Each purchase holds information like
    • Which product was purchased: "product_id"
    • When was the purchase made: "original_purchase_date"
    • Whether or not the auto-renewing subscription is running the trial period: "is_trial_period"
    • The date of the auto-renewing subscription expires: "expires_date"
    • What was the intent behind the subscription expiration: "expiration_intent"
  • Now all that is left is to parse the JSON response and iterate through the contents of "latest_receipt_info" field. Here's the code that does it.

Thats about all that is needed to perform receipt validation.

However, please note that, since we can't build a trusted connection between a user’s device and the App Store directly, we should should always call AppStore receipt validation API from a trusted server. Details of how to do that, is out of scope of this post.

Monday, December 31, 2018

How To Reorder cells in UICollectionView using Swift

While building out a feature, in one of our Apps, I was faced with a need to reorder the cells in UICollectionView using Swift.

I looked around and found many ways of doing it, some of them work and some of them didn't. Heres an implementation that we ended up using and which is working for sure.

The Solution

Here are the steps to get the reorder feature working using drag and drop

  • We need to implement the method collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool from the UICollectionViewDelegate protocol, to indicate that the cells in UICollectionView can be moved around.
  • Next, we need to implement the UILongPressGestureRecognizer for the UICollectionView so that we can better handle the long press gesture
  • We are adding the gesture recognizer to the UICollectionView and setting up the callback method to handleLongGesture(gesture: UILongPressGestureRecognizer)
  • In the callback method we are letting the UICollectionView know about the interactions. 
  • Most of the work is already done, only thing left is to handle what should happen when the items are moved around. This can be achieved by implementing the method collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) from the UICollectionViewDelegate.
Thats about all the code thats needed to achieve reordering of cells in UICollectionView using Swift!

Tuesday, October 30, 2018

How to debug a web page on iOS - Part 2

In this post we will continue our pursuit to debug a web page on iOS. Wont it be nice, if we had Chrome Developer Tools kind of interface even for the iOS?

The second way to investigate webpage errors on iOS is going to achieve exactly that, but using Safari!

The Solution

Apple natively supports remote debugging of webpages on  iOS since iOS6. Here are the steps that are necessary to enabled it.
  • Open Settings app on iOS device
  • Click on Safari

  • Here, click on Advanced

  • Next, enable the Web Inspector switch.
  • Now, head over to your Mac and open Safari.
  • Click on Safari --> Preferences

  • Click on Advanced tab and enable Show Develop menu in menu bar 

  • This will Show a new menu item called Develop right next to the Window menu item.
  • Now, Connect your iOS device with the Mac using a cable.
  • Next, Open the Safari browser on the iOS device and open the webpage that you want to investigate.
  • Click on Develop and you should see your iOS device listed there.
  • Clicking on your iOS device name under the Develop menu, should show up all the web pages opened on the iOS safari browser.

  • Click on the webpage that you want to debug, this opens up the Safari Web Inspector 
  • Here, you can select elements, manipulate CSS, investigate console errors, look at all the network calls, profile your app and more. 
  • Notice when we inspect a div in the Web Inspector, it automatically gets highlighted on the iOS device



    Nice isn't it?

    Sunday, September 30, 2018

    How to debug a web page on iOS - Part 1

    One of our customer, recently wrote an email to our support team about a problem they were facing. They were not able to view the "Printables" section of Monster Math Games. This section shows list of free and paid Printable activities. This page is designed as a web page instead of a native screen and loads in a web view on the app. The customer was only getting a blank white page.

    I started investigating the issue, initially I thought it might be some sort of network latency issue or  something related to HTTP vs HTTPS. But it turned out, the problem was with one of Javascript API we were using.

    The Problem

    Debugging a web page on iOS device, is not as straightforward as I had initially thought. I learned two very interesting ways of debugging webpage errors on iOS. This post is an attempt at documenting these two approaches so that it could help someone who is facing a similar problem.

    The Solution

    The first thing I wanted to check was the actual source code of the web page. Here are the steps we need to follow to view HTML source of a web page.

    • Open this post on the iOS safari browser
    • Click the upload icon button on the menu bar, then click the "Add Bookmark" button.
    • Change the Title field to "View Source" and hit "Save"
    • Next we need to edit this bookmark and change the Address field to the following javascript code. Copy all the text from the following gist.

    • It needs to be done this way because, iOS Safari doesn't let us edit the Address field while creating the bookmark.
    • Click on the "Book Icon" in the menu bar to bring up your bookmarks. 
    • Click on "Favorites", you should see the newly created book mark "View Source".
    • Click the "Edit" and then tap on "View Source" bookmark.

    • Now select the Address field and paste the copied code.
    • Hit the "Done" to save the bookmark.
    • Visit the web page whose HTML source you want to view.
    • Once the page opens, click the newly created bookmark "View Source". 
    • This will open up a popup with details of the web page

    • This Popup has a "View Source" tab that shows the HTML source of the web page.

    Pretty cool, huh!

    Friday, July 29, 2016

    Monster Math - Journey to the Android launch!

    Its been a thrilling roller coster ride for all of us at Makkajai.  I remember the days when we were building our first game Monster Math Classic on iOS,

    • We had no clue of how to develop a game?
    • How to market it?
    • How to get customers etc.  
    All we knew was that, we had an idea and a lot of determination to execute it :D

    In November 2014 we launched Monster Math Classic our first game on iOS.  Even though this was our very first game, we still managed to get lot of love from parents, teachers and students.  They had very kind words to say about our game.  Not just that, they also gave us some very awesome feedback, which could take user engagement to the next level.  We heard our customers and we incorporated their feedback which made them even more happier.

    Somewhere in October 2015 we launched two new games Monster Math and Monster Math Multiplayer which got an even better acceptance than Monster Math Classic.  All these were still iOS only games.

    One question which kept on coming from our customers was: When is it getting launched on Android!

    It was not as if we didn't want to launch on Android.  We wanted to, but since our game was using Cocos2d (A game engine only for iOS), we couldn't do it just by a flip of a switch.

    Somewhere in March 2016, we decided we need to launch our game on all major platforms, so that more and more kids can take advantage of our solution.  We started the effort on porting Monster Math solution to Cocos2dx.

    When I first started to port, it felt like a never ending task.  We had around 50K+ line of Objective C code to be ported to C++.  Just the though of doing this humongous task -- that too all alone -- gave me nightmares :D.

    There were many many problems to solve before we could could even compile an APK.  But as our dear friend Mark Watney (The Martian) says:

    At some point, everything's gonna go south on you... everything's going to go south and you're going to say, this is it. This is how I end. Now you can either accept that, or you can get to work. That's all it is. You just begin. You do the math. You solve one problem... and you solve the next one... and then the next. And If you solve enough problems, you get to come home!

    So thats exactly what we did, we started solving one problem at a time.  First problem was how can we quickly port Objective C code to C++ with minimal effort?

    Instead of manually re-writing 50K+ line of Objective C code to C++, I wrote a quick and ugly Objective C to C++ translator.  It reads and parses any Objective C file and translates code into C++.  Simple right?  This translator does not generate compilable C++ code (because that would be difficult and time consuming).  It only get 90-95% of the job done!

    This one step alone saved us few months of mundane work :D

    • After the initial translation was done, I manually fixed the compilation errors.  
    • Replaced Core Data/Realm with SQLite.
    • Added memory management code, since there is no ARC to cover us.
    • Replaced various SDK's with cross-platform equivalent.
    • Where a cross-platform equivalent SDK was not available, we used platform specific code to integrate native SDK's.
    After solving innumerable such small problems, on July 14 2016 (after around 4 months of starting the project) we launched Monster Math on Android!

    I am very grateful to have gotten this opportunity, I learned (and unlearned :P) so many things in such a short duration.  I am super excited (and proud at the same time) to have achieved this feat.

    Finally, I hope Monster Math on Android gets even more love from its users.  Keep Calm and Have Fun!

    Tuesday, May 31, 2016

    How to write to Google Sheet from an iOS app - Part 3

    In the previous post we saw how we could extract various identifiers from the Google Form.  We will use these identifiers from the iOS app to do HTTP POST and submit information to the Google Form.

    How to do HTTP POST to Google Form from iOS App

    This is by far the simplest step of all.  We will be using the open source iOS library AFNetworking for doing the actual POST.
    • We first need to build a dictionary of all the POST parameters we want to submit to Google Forms using the identifiers extracted in the previous post
    • Then we need to set proper request and response serializers
    • We need to set the content type as "text/html".  Thats because Google Form will return HTML response
    • And finally we need to make the actual POST call.  AFNetwork accepts success and failure callbacks will will be called depending on whether the call succeeded or failed.
    Once this is setup, test it out, on successful POST the data should be getting written to the backing Google Sheet.

    Thats all folks.  We have concluded our three part series of how to write to Google Sheet from an iOS App!

    Friday, April 29, 2016

    How to write to Google Sheet from an iOS app - Part 2

    In the previous post we saw how we could setup the Google Form to write to Google Sheet.

    We will need 2 additional steps to submit information to Google Form from iOS app.

    • Extract the various identifiers (like URL, field id etc) of Google Form
    • Use the identifiers in the iOS app to do an HTTP POST to Google Form
    In this post we will focus on the first step only.


    Extract Identifiers From Google Form

    • All we need to do is click on the "Preview" button on our google form page.


    • It should open up our form as below


    • Right click on the form and say "Inspect".


    • If you are using Chrome brows, it should open up a panel below the page which looks something like this


    • Find a tag called "<form>" in the panel, there you should look for "action" attribute.  This attribute has a big URL as its value.  Save this URL we will to POST to this URL from our iOS app.


    • Next, Right click on the input field in your form and click "Inspect".  It should show "input" tag highlighted in the panel below.


    • We are not really interested in the input tag that the panel is showing, 
    • We need to find another input tag which is of 'type="hidden"'.  This input tag would be 8-9 lines below the input tag currently highlighted


    • Note down the value of "name" attribute on the input.  Do the same thing for other fields in the Google Form.  These keys will be used when we submit information from our iOS app to this form.

    Once we have these identifiers noted we are left with one last step i.e. to do the HTTP POST from iOS app to Google Forms.  We will see how to do that in the next post.

    Thursday, March 31, 2016

    How to write to Google Sheet from an iOS app - Part 1

    Recently we wanted to write some information to Google Sheet from our iOS app Monster Math.

    There does exist an Objective C library that could directly write to the Google Sheet, but the API it exposes did look cumbersome.  What we did instead was a very simple hack.

    • We setup a Google Form with all the information we wanted to write to the Google Sheet.  
    • We then configured Google Form to write the responses to a Google Sheet.
    • This enabled us to directly submit information to Google Form using HTTP POST and responses will get written to Google Sheet automatically!
    In this series I will explain how we could do the above steps.

    Creating the Google Form

    This is gonna be the super easy part.  
    • Login with you google account here
    • Click the big Plus icon to add a new form
    • Set the title as "My Survey".  If you want you can also add optional form description.

    • Next its time to setup questions which will act as columns in your Google Sheet
    • Lets setup two questions "Name" and "Age".
    • Enter "Name" in the text field that reads "Question". 
    • Change the type of the Question from "Multiple Choice" to "Short Answer"

    • Similarly add one more question with title "Age" and of type "Short Answer".
    • After the setup your from should look like the image below.

    Our Google Form is ready for use.  Now we just need to link it with a Google Sheet so that our responses get written there.

    Link Google Form with a backing Google Sheet
    • Click on the "Responses" tab.
    • There you should see a green Google Sheet icon, click that.

    • It should prompt you to create a new Google Sheet with name "My Survey (Responses)", create it.

    • This should open up a Google Sheet which looks something like the image below.

    Verification

    Thats about it, you have successfully setup Google Forms to write its responses to Google Sheet.  You can verify the setup by clicking the preview icon on the Google Form.



    It should open up the form which should look like the image below



    Go ahead and submit some dummy information to test the setup.  This information should be written to the Google Sheet automatically.



    Congratulation on reaching this far, the configuration part is over.  All we need to do is hook up this form from iOS app, we will cover that in the next post. 

    Saturday, October 31, 2015

    How to fix Cocos2.1 shader crash on iOS 9 - Part 2

    In my previous post, I explained how to fix the open GL Shader related crash on iOS 9.  This crash was specifically occurring for apps using Cocos 2.1, the crash fix did work correctly on iOS8 and above.  But the fix had introduced another crash on iOS7 devices.  The crash report looked like this:

    I investigated the issue for sometime and then I had my "duh!" moment.  The code that fixes the crash on iOS 9 used the method "containsString" of NSString class to find whether string A contains string B (on line no 18).

    The method "containsString" was only introduced in iOS 8 hence, it was not available on devices running iOS 7 and below.  When the code tries to use that method it obviously crashes the app!

    We changed the code to not use "containsString" and used "rangeOfString" instead.  This method was supported on iOS 7 as well.  The updated code looks like this:

    Heres the fully updated code that works on all devices running iOS 7 and above.
    Such a silly mistake this was!

    Wednesday, September 30, 2015

    How to fix Cocos2.1 shader crash on iOS 9

    We have been using Cocos2D 2.1 for our game Monster Math.  Recently we decided to release an update to the game by compiling it against iOS 9.  To our surprise the game started crashing right at the launch with the following error.

    A little investigation showed that it was crashing while creating OpenGL shaders.  A little googling proved that others were facing the same issue (more details here and here).

    Whats the Fix - How Do They Do It! 

    To fix the crash, I had to modify code in file CCGLProgram.m of Cocos2D and change the method compileShader as follows.

    Once I made the change, the crash disappeared and it stared launching the game without any problems.

    After this change we released an update of our game to AppStore.  We did however see a few crash reports around this very same issue from devices that were running iOS 7.

    Will have to investigate further and fix it for iOS 7 devices as well.  Will keep you guys posted on what we did to fix it for iOS 7 devices, till then, have fun!

    Saturday, May 30, 2015

    How we reduced the size of our iOS app Monster Math from ~108MB to ~39MB - Part 3

    This is the third and final post in the series of posts where, I will explain, How we reduced the size of our iOS app Monster Math from around 108MB to 39 MB.

    In the previous post, I explained how we first converted our 24bit PNG images to 8bit PNG and then converted those 8bit PNG images to WebP images.

    If you didn't get a chance to catchup on this series yet then, I suggest first read Part 1 and then Part 2 and then continue reading this last post.

    Convert All Sounds and Music files from WAV (or any other format to) AAC Format

    I said this in the first post and I will say it again, "WAV files are huge, don't use them period!".

    We converted all the WAV files into AAC format.  This gives us enormous savings of around 70-80% per file!

    To convert WAV files to AAC, we will use the Audio File Converter (afconvert) tool which comes pre-installed with MAC.  A small shell script to convert all WAV files to AAC would look like this
    This simple shell script will find all the WAV files in a given directory and passes them to afconvert which converts them into AAC format.  

    The results are awesome, you got to see it to believe it!

    Reducing bit rate of AAC Voices to 32K

    We had like a ton of voices in our app in AAC format.  Reducing the bit rate of all these AAC voices to 32K give us another 70-80% reduction in the file size!

    To reduce the bit rate we will use the same afconvert command with a slight modification.  This command has an option via which we can specify the bitrate to be used.
    Only real difference between the previous and this script is the option "-b 32000".  This will make sure that all the converted files will have 32000 as the bit rate!

    These were the last two important methods that gave us significant size reductions in the final binary.

    Thats all folks, have fun reducing the size of your binaries!

    Thursday, April 30, 2015

    How we reduced the size of our iOS app Monster Math from ~108MB to ~39MB - Part 2

    This is the second post in the series of posts where, I will explain how we reduced the size of our iOS app Monster Math from around 108MB to 39 MB.

    The previous post, I described the steps we took to get the size improvements, in this post I will try explain a few steps in a bit more detail. 

    Converting 24bit PNG's to 8bit PNG's

    Of course its possible to update each image manually and save it as 8bit PNG using PhotoShop, but let me put it this way, it wont be convenient, doing it this way.  We had like a ton of images to be converted, so best option would have been a command line tool that we could invoke using a shell script.

    With that in mind, we used pngquant a command line utility that does lossy compression of PNG files.  It conveniently converts 24bit PNG files into 8bit PNG files with a simple command.  

    This simple shell script will find all the PNG files in a given directory and passes them to pngquant and converts them into 8bit PNG images.  

    The results are pretty sweet, it save around 70% of the size of the original 24bit PNG image.

    Converting 8bit PNG's to WebP

    As mentioned in the earlier post, WebP is an image format that provides lossless and lossy compression for images.  Using the lossless compression on an 8bit PNG gives a whooping 26% reduction in image size.

    To convert PNG images into WebP download and install the utilities provided by Google from here.  The simple shell script to convert PNG images to WebP looks like this
    This script basically finds all the PNG images in the folder and passes it on to the WebP converter and creates new files with .webp extension.

    To render webp images using UIImage use the iOS-WebP library or any other similar library.  Our game uses Cocos2d, to add WebP support to Cocos2d just refer this post

    These were the two important methods that gave us significant size reductions in the final binary.  In the next post, I will talk about how we reduced the size of music and sound files of our game.

    Sunday, March 29, 2015

    How we reduced the size of our iOS app Monster Math from ~108MB to ~39MB - Part 1

    Somewhere in November we released our iOS app Monster Math.  When we first released the app it was about 108MB large.  With so many high resolution images and sound and music files that it was bound to be a big binary file.

    We knew from the very beginning that, having a binary this big is not ideal.  Some of the common problems with having big binaries are:
    • The time taken for end users to download and start using the app, linearly increases with size of binary.
    • People just don't sit around and watch the app being downloaded, they browse/download other apps, do other stuff, if the download takes longer we might end up getting a download but losing a user.
    • Not to mention the space that it takes up on the device.  Might not be such a big problem for the iPads but certainly a concern for iPhones.
    • Time taken to distribute the alpha/beta/prod builds increases with the size of binary.
    These are just a few points but the list can go on and on.  After a few releases, we started actively looking for ways to reduce the size of our binary.  We evaluated numerous options and finally managed to reduce the binary size to around 39MB only!

    How Do They Do It!

    This post is a developer log of all the things we did to actually get us such great savings on the binary size!

    NOTE: Detailed examples of how to do each of the following steps will be covered in subsequent posts.

    Identify Biggest Assets In The App
    • This one is by far the easiest step of all, we can easily do a file system sort by size descending, on all the files that get shipped into your application.
    • No surprises here, as expected, biggest chunk comes from
      • Image files
      • Music files
      • Sound files

    Converting 24bit PNG's to 8bit PNG's
    • All images in our application were in PNG format.  
    • One option was to convert them to JPEG to reduce the size, but I was not too keen on that.
    • Digging a bit deeper we realised that all our images were PNG 24 bit.  
    • We changed all of them to PNG 8 bit
    • We could not see any huge drop in quality - not that we are any experts on the topic - but for a regular user it didn't make much difference.
    • This single step will get you around 70-80% reduction in size of all the image assets in your application.  Awesome isn't it!

    Converting 8bit PNG's to WebP
    • We were still not satisfied with our final binary size, so we went hunting for more optimisations.
    • What we stumbled upon was a new image format called WebP from google.
    • Its an awesome format, provides lossless and lossy compression for images.
    • The lossless compression is a whooping 26% smaller than the PNG's.
    • To use WebP in your iOS app you will need to integrate iOS-WebP or a similar SDK.
    • This added awesomeness, did come with some headaches.  
      • The performance of the game took a bit of a hit, because of added overhead of decoding WebP images
      • This was more apparent when bigger images needed to be decoded for e.g. the backgrounds of scene.
      • To get around this problem we eagerly decoded some of the most commonly used WebP images into PNG's on first launch of the game.
      • And from within the game we use these decoded PNG images.  This solved the performance issue to a great extent.
    I know you are itching to look at the code of how we did all this, but please bare with me till the subsequent posts to see the details of each step.


    Convert All Sounds and Music files from WAV (or any other format to) AAC Format
    • WAV files are huge, don't use them period!
    • Converting them to AAC format gave us big savings around 70-80% on each file.

    Reducing bit rate of AAC Voices to 32K
    • We noticed that reducing the bit rate of all voices (yep! we have voice overs in our app) to around 32K didn't impact the quality much (Note that we only reduced the bitrate of Voices not the background music).  
    • They felt the same when they were played back - again no experts on the subject - but for a normal user it didn't seem to make much difference.
    • This give us another 70-80% reduction in size per voice file!
    Seem like a lot of work?  But the end result is equally rewarding, we did manage to reduce the size of our binary to be just under 40MB!

    We started from ~108MB and came down to ~39MB, its like more than 63% reduction in the final size!

    As mentioned early, watch out for the next set of posts where I will explain in detail on how to perform each of the above steps with code examples.  Till then, keep rocking!

    Sunday, November 30, 2014

    How to show realtime translucent background frost/blur effect similar to iOS UIToolbar

    In our app "Monster Math - Best Arithmetic Game. Ever" we wanted to show a parental gate screen, when people click on the "Upgrade" or "Restore" button.  The parental gate screen should have a realtime translucent background frosted glass/blur effect, similar to how its shown in the UIToolbar.

    So essentially what I wanted was something like this.

    The actual view with a carousel, Upgrade and Restore buttons on it

    The parental gate with a translucent background frost effect similar to iOS UIToolbar
    I searched around, to see if I can find an inbuilt API in iOS that can help us do this.  But unfortunately there is nothing exposed by Apple that helps us do it.  That said, Apple did show a simple trick that can give us the desired effect very easily.

    How do they do it!

    This can be done in 3 simple steps
    • Convert the underlying UIView to an UIImage
    • Frost/Blur the UIImage
    • Set this new frosted/blurred UIImage as background of your new view
    NOTE: The explanation of how to do these steps can be found in this SO Answer.


    Convert the underlining UIView to an UIImage


    This can be done by creating a new category of UIView and adding the following method to that category


    Frost/Blur the UIImage


    To frost/blur the UIImage that we created in the previous step we can use the Apples Image Effect category.  The code for ImageEffects category looks as follows

    Using this ImageEffects category we can frost/blur any UIImage as follows


    Set this new frosted/blurred UIImage as background of your new view


    This is by far the simplest step of all.  All that needs to be done here is to set the newly created UIImage as the background of your new view.  Our game is developed with Cocos2d and we could do this using the following lines of code

    The end result is very satisfying.  It looks great on the devices as well!

    Thats all folks! I hope you like this realtime frosted glass/blurred effect as much as I do.

    Friday, October 31, 2014

    How to get Apple Cover Flow effect in an iOS app

    Recently, for our flagship app Monster Math, I was on a hunt to find a control that gives me the Apple Cover Flow like effect.  After evaluating a few options I ended up using the awesome iCarousel control.

    Its extremely customisable, lightweight, has numerous hooks and many many predefined effects, its simply awesome!  In this post, we will see how easy it is to get the iCarousel integrated into our app.

    How Do They Do It!

    To get this control up and running follow these simple steps

    Installation

    The installation is stock standard, you can install it via Cocoapods.  Use the following line in your pod file

    and then run

    Usage
    • There are two protocols that need to be implemented for the iCarousel to work correctly.  iCarouselDataSource and iCarouselDelegate
    • The iCarouselDataSource protocol has two mandatory methods to be implemented 
      • (NSInteger)numberOfItemsInCarousel: This method returns the number of items in the carousel 
      • (UIView *)carousel:viewForItemAtIndex:reusingView: This method returns the view that needs to be shown in the carousel.
    • The iCarouselDelegate protocol has no mandatory methods but its good to implement the following method
      • (CGFloat)carousel:valueForOption:withDefault: This method can return values for different options which alter the display and behaviour of the carousel.
    Thats about all the methods we will need to implement to get the cool Apple Cover Flow effect.  Lets jump into the code to see the details of implementation


    In this snippet we are just initialising the iCarousel and setting the type of carousel to iCarouselTypeCoverFlow2, this type's behaviour closely mimics the App Cover Flow effect.

    Next up are the protocol methods that we described earlier.

    This snippet implements the two mandatory methods of iCarouselDataSource protocol.  For the view we are showing a simple image from our assets.  And we have total 4 items in our carousel.

    The last and final method just customises two options of the iCarousel.  It basically wraps the view so that we get an infinite view sort of a feeling and adjusts the spacing between the views a bit.

    With all the pieces in place lets fire it off and see how it looks!

    An Infinite Cover Flow Effect

    An Infinite Cover Flow Effect

    Pretty impressive for such little code, won't you agree?  

    That's all folks, until we meet again, Guten Tag!

    Sunday, March 30, 2014

    Passing CGFloat to methods resets the value of arguments to 0

    Recently, I was faced a very weird issue with methods that have CGFloat as argument.

    The Problem

    We were using cocos2d for our iOS project.  The code was very simple, I was trying to invoke a method of class that takes two CGFloat arguments.

    No matter what values I pass to doSomething it always receives 0 or some other garbage value.  Just to be extra sure, I even logged the values of the parameters passed before actually invoking the method.  The values got printed correctly, but the doSomething method always printed 0.

    The Explanation

    Well, I was stumped here.  This was like the simplest possible code.  Set the value of a variable, pass it to another method and BOOM the value gets reset!

    Obviously, this was nothing to do with how I have written the code, others out there must be facing the same issue.  A bit of googling calmed my nerves.

    CGFloat is just a typedef wrapper around either a float or a double. Whether it actually is a float or a double depends on the header where CGFloat is defined that your code compiled against.  The CGFloat definition looks something like this

    Notice how CGFloat either becomes a float or a double, depending on whether the architecture is 64 bit or not.

    All goes well, until you mix code compiled with this flag on, with other code compiled with this flag off (Such as including a binary library with other code). Effectively mixing 64 bit compiled code with 32 bit compiled code.

    This can potentially lead to a case where we are passing doubles to methods that are expecting a float.  Since this is all happening at the byte level, no error is thrown and the bytes are just truncated, taking off all of the bits that actually described your value and leaving bits with nothing in them i.e. 0.

    In my case, it was happening because I was trying to build a binary for both the Simulator and iPad Air Device.

    The Solution

    A clean and build should have solved the issue, but I decided to change the method arguments to float instead of CGFloat.  Once I did this change, everything worked as expected!
    Thats all folks!  Until we meet again, enjoy your time.


    Sunday, February 23, 2014

    How to play game voices sequentially when background music is running on iOS

    I was recently hacking my way through an open-source iOS game and I was faced with two interesting problem.
    • There are multiple voices and background music that are played at different times.  It was becoming extremely difficult to hear the voices clearly when the background music was turned on.
    • To add to that, there are certain voices that needed to be played in sequence.  For example, when user reaches "Level" "n", we want to play a voice "Level" and then the level number where the user has reached.  For example, if the user has reached Level 3, we want to play "Level" and then "3" since we do not have a distinct voice for every level (may be that's not even scalable).
    In this post, we will see how we fixed both this issues using a small wrapper class.

    How Do They Do it?

    What I ended up doing was to create a small wrapper class that had following main responsibilities:
    • Fades-out the background music to slower volume whenever a voice is playing
    • Fades-in the background music to original volume when voices have finished playing
    • Manage a queue or a playlist of voices which are played in sequence.
    We made use of the CDAudioManager class its delegates to implement this class.  Once we had this class in place, it made task really simple.  The code was well encapsulated and we could use it throughout the system consistently.

    Without wasting any more time, let's have a look at how actually its done!

    Create the Singleton AudioManager

    This class needs to act as a service to the application, hence we are going to make it a singleton class.
    Initialize Fields
    • Next step is to initializes the CDAudioManager 
    • Build NSMutableArray that will hold the queue of voices for us.  
    • We will also be registering AudioManager as a delegate to the CDAudioManager class.  Hence, we will implement the protocol CDLongAudioSourceDelegate
    Enqueue Voices
    • This is where we build the queue of our voices.  
    • If the audioSource is not busy playing any other voice, then we simply play the voice.  When we play the voice we will also make sure that we fade-out the background music to a lower volume.
    • Else we will add the voice to the queue of voices
    Implement the Delegate
    • This is where it all comes together.
    • We implement the protocol CDLongAudioSourceDelegate, this protocol has two optional methods
      • cdAudioSourceDidFinishPlaying
      • cdAudioSourceFileDidChange
    • We are only interested in implementing the cdAudioSourceDidFinishPlaying method.  This method will be called every time CDAudioManager finishes playing a voice.
    • Every time this method is called, we know that CDAudioManager has finished playing a voice we can now play the next voice from the queue.
    • If the queue is empty, then we simply fade-in the background music to its original volume.
    That's about all that we need to do!  We have successfully setup the AudioManager for voices in our game.  It will nicely play voices one after the other and fade-out the background music when the voice is playing.

    For sake of completion and easy understanding, here is the full code for the class
    Have some Fun!