Monthly Archives: July 2014

Errors and Exceptions in Objective C

Undestanding The Difference

There are two types of bad situations in an Objective C program: errors and exceptions. Let us understand the difference between the two.

Error is an unwanted situation that can happen during program execution but you can recover from it. The program memory remains in a consistent state and further execution can continue.

eg1: Attempt to access a network resource timed out or returned 500

eg2: Attempt to write to disk failed due to lack of disk space or permission denied

Handling: You can handle errors any way you want. Show a user message, log it to a file/console or report it to your back-end.

Exception is an unwanted state in your program that should never have occured. Exceptions may corrupt the memory state of the program in a way that prevents further execution.

This can generally occur in two ways:

  1. A logic error that you overlooked is now causing an exception.

    eg: Accessing invalid array elements i.e. index out of bound exception.

    In the above example, you unconsciously made a programming mistake. You couldn’t have handled it because you overlooked it. This will crash the program.

    Handling: Your approach here should be to reproduce and fix it asap.

  2. While execution, your program comes across a situation that your business logic doesn’t permit.

    eg: A database entry that your business logic expects to be always present is missing. For example, let’s say you are writng a program that requires a currency table with currency names, unicode symbols for currencies and country names. The values from this table are to be shown in a drop down in your program UI. You may create a table upon first launch of the program and insert the values. Later you make an sqlite select query but no values are returned.

    This is where confusion may arises because you can recover from such situations by treating them as errors (because the program memory is not corrupted) and displaying a message to the end user. This approach is wrong because it’s an exception at the business logic level.

    Handling: In such cases, you should force crash the program using NSAssert both in development and production phase. This is an aggressive approach geared toward quickly finding and fixing such exceptions rather than disguising them as errors. Besides, treating them as fatal (crash) attributes them the urgency they deserve.

Some Other Tips

  1. Try to avoid using @try/catch in Objective C because experts don’t recommend it.
  2. Formalize an approach to error/exception handling and stick to it. Document your intent in the code. You will be better off finalizing an approach and employing it consistently rather than revisiting this subject again and again.

Webservices Checklist

In my last job, I helped create some webservices. In the process, I learnt a thing or two about webservices. Here is a list of things that can help you create better webservices

  1. Standards compliance
  2. Consistent with one anonther
  3. Fast and Efficient
    • Response time
    • Memory allocation
    • Algorithm
  4. Load testing
  5. Validations
    • Client level
    • Server controller level
    • Server model level
  6. Request format
  7. Request validation
  8. Response format
  9. Response validation
  10. Exception handling
    • Server logging
    • Server mail alerts to developers
    • Recovery
    • Response to client
  11. Versioning
  12. Webservices update strategy
  13. Dependencies: third party frameworks and their deprecations
  14. Deprecation of webservices
  15. Scalability
  16. Documentation
  17. Security

Mac App Store Receipt Validation

When you develop a Mac app, particularly paid app, it is important to ensure that users install genuine copies of your app via the right channel. Apps distributed outside of the Mac App Store achieve this by issuing Licenses to users which they need to enter into the app before they can start using it. Apps distributed via the Mac App Store achieve this using Mac App Store receipt validation.

Every app that is downloaded from the Mac App Store is provided a receipt that resides in the app bundle at /Contents/_MASReceipt/receipt. The receipt is cryptographically signed ensuring that only Apple can create it. Developers are required to write code to validate the receipt which guarantees that the copy of the app is valid and installed via the Mac App Store. Without this check by developers, apps can be downloaded once and passed around to other users bypassing the Mac App Store. Recently, I integrated receipt validation in my Mac App. This post attempts to summarize the knowledge I acquired in the process.

Receipt validation can be done in two ways

  1. Validating with the Mac App Store: From the app, you can pass the installed receipt to your server which can perform the validation by communicating with Apple servers and notify the app about the validation result.
  2. Validating locally in the app: You can write the receipt validation code locally in the application code.

This post only covers validating receipts locally. For validating receipts with the Mac App Store, check this. It is recommended by Apple that receipt validation be performed as soon as the app is launched. The validation code should be added to the main() function before NSApplicationMain() call.

Validation Steps In Order

  1. Locate the receipt and verify that it is properly signed by Apple.
  2. Verify that the bundle identifier, version identifier strings in the receipt match the CFBundleIdentifier, CFBundleShortVersionString values respectively in the Info.plist file.
  3. Compute the hash of the GUID and verify that it matches the hash in the receipt.
  4. Note: The GUID is uniquely tied to the hardware on which the app is originally installed from the Mac App Store ensuring that copied apps don’t work due to GUID mismatch.

If all of the above steps pass, validation succeeds.

Handling Validation Failure

Sometimes it may happen that a valid install fails to write the Mac App Store receipt to the app bundle resulting in receipt validation failure when the app runs. In such cases, you should call exit with a status of 173. This exit status notifies the system that your application has determined that its receipt is invalid. At this point, the system attempts to obtain a valid receipt and may prompt for the user’s iTunes credentials.

The system relaunches the application if it successfully obtains a valid receipt. Otherwise it displays an error message to the user explaining the problem. You should not display any error message to the user on validation failure because this duty is delegated to the system. The system is responsible for trying to obtain a valid receipt or informing the user that the receipt is not valid.

Things To Remember

  • Don’t Localize Your Version Number

    If your application is localized, the CFBundleShortVersionString key should not appear in any of your application’s InfoPlist.strings files. The unlocalized value from your Info.plist file is stored in the receipt. Attempting to localize the value for this key can cause receipt validation to fail.

  • Protect Your Validation Check
    1. Inline the code for cryptographic checks instead of using the APIs provided by the system.
    2. Avoid simple code constructions that provide a trivial target for patching the application binary. For example, avoid writing code like
      if (failedValidation) {
              exit(173);
      }
          
    3. Use code obfuscation to avoid reverse engineering.
    4. Ensure that even if the exit function fails to terminate your application, your application stops running. You may use abort().

Testing Receipt Validation During Development Phase

In order to test your Mac app during the development phase, you need a valid receipt so that your application launches. To set this up, do the following

  1. Make sure you have Internet access so you can connect to Apple’s servers.
  2. Create a test user in iTunesConnect > Manage Users section.
  3. Launch your application by double-clicking on it.
  4. Your application fails to validate its receipt because there is no receipt present and exits with a status of 173.
  5. The system interprets the exit status and attempts to obtain a valid receipt by prompting you to enter your iTunes credentials. You should provide the test user’s (step 2) details here.
  6. Assuming your application signing certificate is valid, the system installs a valid receipt for the application.
  7. The system relaunches your application, and your application successfully validates the receipt.

Receipt validation is a crucial step in Mac app development process and I hope this post makes implementing it easier for someone. Here are some libraries to get you started in the right direction. GOOD LUCK AND GOOD LIFE!!!