Browse Author: mayur.kore

How to create Passes for passbook in iOS6

Passes are everything in your pocket

Apple’s simplified explanation of passes is that they are “everything in your pocket.” I like that line very much, because it demonstrates so well how imaginative you can and should be about creating your pass applications and services. Passes can be anything.

But what are they, anyway?”, you might ask.

Well, here’s how a pass looks on the iPhone:

You can easily spot a few different elements on the front of this pass that give you important information: a logo and a company name on the top, the words “Free hug!”, which clearly denote what this pass is all about, and also information concerning its validity (start date, duration).

Then there’s that barcode at the bottom. It’s much like the barcodes you’re already used to seeing on train tickets, airplane boarding passes, store cards, etc. If you think about it, a pass on your iPhone can carry the same information as any of those paper passes you are used to stuffing in your pockets, right? Some text, a barcode – and that’s it. Trust me, though: a digital pass on your iPhone can also do a lot more.

What makes a pass, a pass

Look again at what’s on the pass below and consider the different sections it has:

All types of passes have these important areas in common:

  1. Top header. A top ribbon containing an easy-to-identify logo and a company name. This header area is the part of the pass a user will see when they open a full deck of passes in Passbook. It includes the most essential info you want to provide to the user, so they can easily spot the pass they need.
  2. Main content area. A section containing the substance of the pass. Each pass type has different styling for this section, and it usually shows the information that you want most prominently displayed once the pass is open. It’s very useful for labels like “20% off,” “One free coffee,” “Balance: $120” or anything else of the sort.
  3. Additional info. The third section is for additional information – material that’s still very important (the validity of the promotion and the start date in the example), but definitely not as important as what the pass is all about.
  4. Barcode. The barcode contains encoded information that can be easily transferred to other systems by scanning it with a barcode reader. In the example above, the barcode contains a secret code. When decoded by a scanner, it entitles the bearer of the pass to one free hug (to be delivered immediately).

By now you’re probably considering which of the paper passes, store cards, etc. that you use on a daily basis can be converted to a digital pass on your iPhone!

Do I board with this pass, or do I get a free coffee?

Before you dive into coding, have a look at the different types of passes.

Apple has defined four types of passes, each for a common use, as well as a fifth type for “generic” use. Why these different pass types, and how do you recognize them?

The pre-defined pass types are each styled to draw attention to different pieces of information that suit the purpose of the pass. There’s a reason why the layout and content of your gym membership card is different from your concert ticket! The first needs your picture on it while the second doesn’t, for example.

Layout is the main way to differentiate between passes, but UI features like rounded corners and paper cutouts also make passes easily distinguishable. The differences are small, but noticeable, and that’s one of the reasons you have to make sure you use the correct type for your pass.

Here are the four pre-defined pass types:

  • Coupon
  • Boarding pass
  • Store card
  • Event ticket

Then of course, there is the generic type of pass. This tutorial will cover all five types in detail in Part 2.

For now, have a look at the boarding pass example below. You can see it’s pretty similar to the hug coupon from earlier, but has some important differences: it features a great two-column layout that makes it very easy to spot the departure and arrival cities; the departure platform number, time and seat number are also well-placed.

By now I am sure you are convinced that passes are a great thing for the iPhone! Now let’s turn to how passes are set up, and how to make one!

The guts of the pass

This section will introduce the building blocks for a pass. A pass comes to the user as a file with a .pkpass extension. (“pkpass” standing for PassKit Pass – totally makes sense, right?)

The .pkpass file is just an ordinary .zip file with a custom extension. If you rename one to ZIP and extract it, you’ll find several files. Here are the contents of the Free Hug Pass you saw earlier:

  • pass.json – the description of the pass information fields, their content, and meta information.
  • manifest.json – the file that describes the list of files inside the pass and the SHA1 checksums of each of those files.
  • signature – a detached DER signature of manifest.json, generated using an Apple-provided certificate.
  • background.png – the image to show on the front of the pass.
  • background@2x.png – the retina-sized image for the front of the pass.
  • logo.png – the logo to show in the pass header. Apple recommends a solid one-color logo. The image size is up to you, but the height shouldn’t be more than 50px in order to fit inside the header.
  • logo@2x.png – the retina counterpart of logo.png.
  • icon.png – a small icon for the pass, used when the pass comes as an attachment in Mail. As of the time of writing, there is still no documentation about the icon’s size, but it looks to be 29×29 pixels (bigger size icons are scaled down, so they look fine as well).
  • icon@2x.png – the retina icon file.
  • strip.png and strip@2x.png – the image strip, used as background behind the primary fields; used only for the coupon and store card passes.

And that’s all!

As you can see, the main file of the pass is the JSON file pass.json. Inside it you declare all the contents of the front and back of the pass. Along with this JSON file, you provide all images the pass should display (in the case of a coupon, you can supply only background.png and its retina counterpart). Finally, you need a manifest file, which states the original SHA1 checksums of all those files above, and a detached signature signed by you, so that Passbook can verify that the pass hasn’t been amended since you created it.

Let’s write some JSON!

You’re at the point where you can write some code. Let’s see if you can reproduce the Free Hug coupon!

But wait! JSON isn’t Objective-C. It’s not even a programming language of any sort. It’s just a markup language used to describe data structures… So, how do you write JSON? Actually, you can use any text editor – Xcode, TextMate, Coda or even TextEdit. In this chapter, you’re going to use Xcode.

From Xcode’s menu choose File/New/File… and then choose iOS/Other/Empty for the file type. Name the new file pass.json and save it in a folder of your choice. Note you probably want to create a new folder to store the pass in, because you’ll be putting a lot of pass-related files in the same folder and it will be nice to keep it all together.

You should now be looking at a tragically empty window, like this one:

But’s that’s OK – no worries!

For those of you not familiar with JSON notation – it’s pretty easy. You can use numbers, strings, arrays, and dictionaries. The information is written out like this:

14.37457 – for numbers
“Some text here!” – for strings
[object1, object2, object3, …] – for arrays

And:

{“key1”: object1, “key2”: object2, “key3”: object3, …} – for dictionaries

Object1, object2, object3 and so forth can be any of the four types of objects above – i.e. you can have arrays of dictionaries, dictionaries that hold arrays, strings, numbers, and so on.

You can read more on JSON here: http://en.wikipedia.org/wiki/JSON

Let’s start with the barebones of the Free Hug coupon! Copy this code into your pass.json file:

 

{
    "formatVersion" : 1,
    "passTypeIdentifier" : "pass.com.yourdomain.couponfreehug",
    "serialNumber" : "001",
    "teamIdentifier" : "<YOUR TEAM IDENTIFIER>",
    "organizationName" : "Free Hugs LLC",
    "description" : "Coupon for 1 Free Hug"
}

This is the bare minimum of meta-information you need to provide:

  • formatVersion – the file format version, and since this is a brand-new file format, you’re using 1 (note that 1 is a number; if you provide a string for the value, the file won’t validate).
  • passTypeIdentifier – this is the identifier of the Pass. It’s pretty similar to the bundle identifier in an iOS app. More will be said about this identifier in a minute.
  • serialNumber – this is the serial number of the pass. You generate this number any way you like – it can be numeric, like “00193” (note that it still needs to be written out as a string value), or a combination of letters and numbers, like the serial numbers you’ve seen on airplane boarding passes (for example, “XS83A”).
  • teamIdentifier – this is the unique 10-character identifier Apple assigns to you as an iOS developer. If you’ve been creating your own iOS apps, you should already be familiar with it. To find your team identifier, log onto the iOS Member Center and click the name of your organization. You will find it there next to a label titled “Company/Organization ID”. I’ll show you another way to find it later on as well.
  • organizationName – the name of the issuing entity.
  • description – a short description of the pass.

This is a lot of information, so let’s see how is it useful to Apple.

Since the passes are not necessarily connected to an iOS app, there’s no automatic way for Apple to connect a pass to a given iOS developer account (which it needs to do to validate the pass contents). Passes might arrive to the user’s device independent from an app, via mail or web download (or another way). This is why the teamIdentifier is included in the meta information inside the pass – to connect the pass instance to an iOS developer.

Once Apple knows the identity of the developer who created the pass, they take the passTypeIdentifier to figure out which type of pass it is (of all the ones defined by a given developer account). Every pass type has its own certificate, so Apple can use this certificate and validate the signature included in the pass bundle – i.e., make sure nobody tampered with the pass contents.

Finally, the serial number is used to identify the unique instance issued for the given pass type.

To recap, consider an example:

  • Joe’s Café has an iOS developer account with Apple. Thus, they use their team identifier on all their passes.
  • They have store cards with preloaded store credit, which users can use to order yummy coffees in the shop. Store cards have passTypeIdentifier “pass.com.joescafe.storeCard”.
  • They also have discount coupons that have a different passTypeIdentifier – “pass.com.joescafe.discountCoupon”.
  • A given user can own more than one store card (for example, they bought one and a friend gave them one as a present), so the serial number is used to distinguish between two store cards of the same pass type (for example, “0134” and “0274”).
  • Passes from the same passTypeIdentifier will be grouped together inside Passbook. When the user is at Joe’s Café, they’ll tap the stack of Joe’s Café store cards in Passbook, and choose the one they want to use – probably the one that still has credit on it!

By now you should understand pretty well how pass identification works. So “pass” this section and move on to the next, where you’ll create your first pass type.

Get me the certificate!

Head to the iOS Developer Portal (https://developer.apple.com/devcenter/ios/index.action), and after you log in, open up the iOS Provisioning Portal from the menu on the right-hand side.

If you’ve already been checking out the new stuff for iOS 6, you might have noticed the new item in the left menu called Pass Type IDs. Click on that link and on the next page, you’ll see a list of all the pass types you’ve already created (probably empty at this point).

Click the New Pass Type ID button and you’ll go to a page where you can create a new type. In the description field enter “Free Hug Pass” and in the Identifier field enter “pass.com.yourdomain.couponfreehug”. For the Pass Type ID, Apple recommends the reversed domain notation with a prefix of “pass.” So that’s the format you’re using.

Note: For the purposes of this chapter you can certainly use “com.yourdomain”, but in production applications remember that you should replace com.yourdomain with the actual reverse notation for your domain. ☺

Also note that if you decide to change the identifier here to something other than “pass.com.yourdomain.couponfreehug”, you’ll also have to update the passTypeIdentifier value in pass.json accordingly.

Next, simply click Submit to create your pass.

By the very way that light indicator is not lit up in green, you might already guess there’s something missing. Yes – you are right. You still need to generate the pass certificates. Click on Configure to do that. The next page that comes up is a good place to spot the full identifier of your pass.

Here you can see your teamIdentifier (it’s the first 10 characters beginning with ABC) and update pass.json with it – make sure to replace only the placeholder and leave the quotes around it!

All right! Your pass.json metadata is now updated. However, there’s still an extra step to get your certificate imported into your development environment.
Back in the iOS Provisioning Portal, click the Configure button:

This will launch the Pass Certificate Assistant (*fancy name!), which will guide you through the process of generating your certificate. Pay attention to the dialog and follow the steps.

After you upload your signing request, your certificate will be generated in a timely manner and you should see the success dialogue:

Click Continue one more time and then click Download to get the certificate file. After the file downloads, find and double click it to import it into the Keychain. Note that it’s most probably in the Downloads folder inside your user folder, unless you’ve set another default download location in your browser.
If Keychain asks you to confirm the import, click the Add button:

And then you should see your certificate in Keychain Access:

w00t – you’re done making your certificate! Now you have real metadata in your JSON file and the proper certificate for when the time comes to sign the pass.

 

{
    "formatVersion" : 1,
    "passTypeIdentifier" : "pass.com.yourdomain.couponfreehug",
    "serialNumber" : "001",
    "teamIdentifier" : "<YOUR TEAM IDENTIFIER>",
    "organizationName" : "Free Hugs LLC",
    "description" : "Coupon for 1 Free Hug"
}

This is the bare minimum of meta-information you need to provide:

  • formatVersion – the file format version, and since this is a brand-new file format, you’re using 1 (note that 1 is a number; if you provide a string for the value, the file won’t validate).
  • passTypeIdentifier – this is the identifier of the Pass. It’s pretty similar to the bundle identifier in an iOS app. More will be said about this identifier in a minute.
  • serialNumber – this is the serial number of the pass. You generate this number any way you like – it can be numeric, like “00193” (note that it still needs to be written out as a string value), or a combination of letters and numbers, like the serial numbers you’ve seen on airplane boarding passes (for example, “XS83A”).
  • teamIdentifier – this is the unique 10-character identifier Apple assigns to you as an iOS developer. If you’ve been creating your own iOS apps, you should already be familiar with it. To find your team identifier, log onto the iOS Member Center and click the name of your organization. You will find it there next to a label titled “Company/Organization ID”. I’ll show you another way to find it later on as well.
  • organizationName – the name of the issuing entity.
  • description – a short description of the pass.

This is a lot of information, so let’s see how is it useful to Apple.

Since the passes are not necessarily connected to an iOS app, there’s no automatic way for Apple to connect a pass to a given iOS developer account (which it needs to do to validate the pass contents). Passes might arrive to the user’s device independent from an app, via mail or web download (or another way). This is why the teamIdentifier is included in the meta information inside the pass – to connect the pass instance to an iOS developer.

Once Apple knows the identity of the developer who created the pass, they take the passTypeIdentifier to figure out which type of pass it is (of all the ones defined by a given developer account). Every pass type has its own certificate, so Apple can use this certificate and validate the signature included in the pass bundle – i.e., make sure nobody tampered with the pass contents.

Finally, the serial number is used to identify the unique instance issued for the given pass type.

To recap, consider an example:

  • Joe’s Café has an iOS developer account with Apple. Thus, they use their team identifier on all their passes.
  • They have store cards with preloaded store credit, which users can use to order yummy coffees in the shop. Store cards have passTypeIdentifier “pass.com.joescafe.storeCard”.
  • They also have discount coupons that have a different passTypeIdentifier – “pass.com.joescafe.discountCoupon”.
  • A given user can own more than one store card (for example, they bought one and a friend gave them one as a present), so the serial number is used to distinguish between two store cards of the same pass type (for example, “0134” and “0274”).
  • Passes from the same passTypeIdentifier will be grouped together inside Passbook. When the user is at Joe’s Café, they’ll tap the stack of Joe’s Café store cards in Passbook, and choose the one they want to use – probably the one that still has credit on it!

By now you should understand pretty well how pass identification works. So “pass” this section and move on to the next, where you’ll create your first pass type.

Time to make it beautiful, baby!

They say an image is worth a thousand words – lucky for you, there’s no space for thousand words on the front side of the pass, so when in need you might as well use an image.

Go ahead and download the assets I’ve prepared for you: PassAssets.zip. Extract the files and inside the FreeHugCoupon folder you will find a bunch of PNG files. Copy them over into your pass work folder.

And that’s it – you’re done! Phew, that was easy.

Wait, what? You don’t have to add any code inside pass.json to tell Passbook which image files to load. That’s right!

Passbook will automatically load image files following standard naming conventions. This means images named icon.png; icon@2x.png; logo.png; logo@2x.png; strip.png and strip@2x.png will be displayed on the pass, if provided. No need to do anything but include these files in the pass bundle. (There’s also few more images that this chapter will cover later on.)

Note: There’s one nasty gotcha about the pass images, which took me a while to figure out – the image files need to be exported as PNG24 format. For some reason the much smaller-in-size PNG8 format just won’t show up in Passbook.

“Let’s give that pass a try! I want to see it already!”, for sure you are crying in despair.

Unfortunately, until the pass bundle is complete, signed and zipped you cannot preview the pass. Passbook won’t display any invalid (incomplete) passes. So muster a little more patience and keep going.

The pass manifest

The pass manifest is another JSON file you need to create, and it describes all the files included in the pass bundle and their SHA1 checksums.

You can make this yourself by generating the SHA1 checksums for each file yourself (as I’ll show you in a minute), but so that you can move faster with building your first pass I’ve included an already-generated manifest.json file in the PassAssets.zip file you already downloaded and extracted. Find manifest.json inside the folder where you extracted the zip file and copy it over to your pass work folder.

It’s contents are as follows:

{
 "strip.png":"25b4c9ff2bafe056f3e28379db0ef3fb460c718b",
 "strip@2x.png":"dee775ed6fb3c7278b84c65853401e760caabc92",
 "icon.png":"8eaa0896db93f2165fa417df3d002ce9c61fcd92",
 "icon@2x.png":"555ce7f70f2f44fb7ac9d9f46df5738ec6250f37",
 "logo.png":"e8c4edfbcae41d9d88fad7137d8ed30ae5f73e67",
 "logo@2x.png":"1f9b1cc4c75b380ade07e9f2b7f37f988d9d14c3",
 "pass.json":"<INSERT YOUR PASS SHA1 HERE>"
}

The SHA1 checksums for the images are already pre-filled, but the final checksum – the one for your pass.json file – is not. You are going to generate its SHA1 yourself. It’s quite easy – open up Terminal and navigate to your pass folder.

Note: If you aren’t familiar with navigating directories in the Terminal, do this: move your pass files into a folder on your Desktop and call it “FreeHugCoupon”, then launch Terminal and enter this command:

cd ~/Desktop/FreeHugCoupon

There you go.

Enter this command at the Terminal prompt:

openssl sha1 pass.json

The output of the command should look something like this (the actual checksum will be different for you):

SHA1(pass.json)= c24766ef5aa92197eace640fcc4fb584a505a733

Select the alphanumeric checksum value and in your manifest.json file replace “” with the checksum string. Save the file and you’re done! (Make sure you leave the quotes alone.)

NB! It’s important that you do not edit pass.json anymore until told to do so. If you add even one character to pass.json, the SHA1 checksum will change and your manifest.json will become invalid, since the checksum given there will no longer match the checksum of the modified pass.json file.

This is the last source file you need for your pass. Awesome!

Can I have your signature, please?

Now comes the most interesting part of creating a pass.

Remember the certificate you got from Apple for your pass type? You’ve imported it to your Keychain and you haven’t touched it since. Now you’re going to export the certificate and the key in PEM format, so that you can use them with OpenSSL.

Open up Keychain Access, select Certificates from the left menu (under Categories) and find the certificate called “Pass Type ID: pass.com.yourdomain.couponfreehug”. Make sure you’ve selected the item itself and not the private key underneath:

Next right-click on the certificate and choose from the popup menu Export “Pass Type ID: pass.com.yourdomain.couponfreehug”… Save the exported file as “Certificates.p12” inside your working pass folder. You’ll be presented with a dialog to choose a password:

To make the process a bit easier, just click OK – the certificate will be exported with no password protection.

Note: At this point you might be prompted to enter the password for the login keychain. If you are, then simply providing your user password should suffice.
The Certificates.p12 file now contains both the pass certificate and your private key. OpenSSL needs those in separate files, so now you have to extract them from the .p12 file.

Switch back to Terminal – it’s time for OpenSSL magic!

After making sure the current directory is the correct one (to double check, enter “ls –al” and hit Enter – you should see the file listing of the folder, and it should contain your Certificates.p12 file), enter the following command:

openssl pkcs12 -in Certificates.p12 -clcerts -nokeys -out passcertificate.pem -passin pass:

That’ll export only the pass certificate in PEM format and save it as “passcertificate.pem” inside the same folder. (OpenSSL will spit out the message “MAC verified OK” if the operation is successful.)

Next, export the key as a separate file with this command:

openssl pkcs12 -in Certificates.p12 -nocerts -out passkey.pem -passin pass: -passout pass:12345

Note that this time, you need to provide a password in order to export the key file. In this case, just use “12345” – obviously for production environments it’s advisable to use a strong password (doh!) – so, nothing of the “password1” or “passw00t” sort, please.

To sign your pass bundle you will need one more certificate – the WWDR Intermediate certificate, which authorizes the issuer of your own certificate – Apple. Chances are you already have it installed in your Keychain. Open up Keychain Access, select the “Certificates” category and look for a certificate called “Apple Worldwide Developer Relations Certification Authority” (yes, this is a quite long name indeed):

If by any chance you don’t have this certificate already imported, then open up in your browser this web page: http://www.apple.com/certificateauthority/. Here you can freely download the most important Apple certificates you might need. Scroll down, find the WWDR certificate, download the .cer file and import it in Keychain.

You’re ready to go on with exporting the certificate. Back in Keychain Access right click on the certificate name and choose the Export option in the popup menu:

In the “Save as…” dialogue find the File format drop box and choose Privacy Enhanced Mail (.pem) option:

In the text field at the top of the dialogue give the file the name “WWDR.pem”, select your working pass directory as destination, and hit the Save button to finish the export.

You’re ready to create the signature. Enter this command:

openssl smime -binary -sign -certfile WWDR.pem -signer passcertificate.pem -inkey passkey.pem -in manifest.json -out signature -outform DER -passin pass:12345

Read through the command line above once more – it’s quite easy to understand all the parameters. The signer parameter is your pass certificate’s file name; inkey is the key file used to sign manifest.json; in is the input file name; out is the output file name; outform is the output format (you need “DER” to create a detached signature); and finally, passin is the password for the key file.

Now you have your signature and the production of the pass is almost complete.

The last remaining step is to combine the various files for the pass into a .pkpass file. Enter this command in the Terminal:

zip -r freehugcoupon.pkpass manifest.json pass.json signature logo.png logo@2x.png icon.png icon@2x.png strip.png strip@2x.png

By using the shell command “zip” you create a ZIP file called freehugcoupon.pkpass and the archive will contain all the files in the list that follows.
Believe it or not… that’s it! High fives all around! You did it!

Show me or I don’t believe it!

Yes, you’ve finally reached the point where you possess a complete and valid pass that you can see on your iOS 6-powered device.

Create an email message to yourself (or to the email account you have set up on your iOS 6 device) and attach the .pkpass file you just created. Send it over, open the mail in Mail.app and voila! You should see the attachment turn into a pass, like so:

If you see the pass show up – congratulations! You’ve made it!

If not, don’t be disappointed – it’s a long and error-prone process, so you’ll have to go back to the very beginning and check that you performed all the necessary steps. Make sure your JSON files are valid and that you’ve exported your certificate and key correctly.

Tip: If you want to check the validity of your JSON files, use an online tool like http://jsonlint.com/ to quickly proof your code.

Time to see the pass! Tap on it inside the email message and Passbook should pop up showing you some greatness!

 

Updates in iOS 6

A lot has happened in iOS 6 and apple has a document which you may read it from here. The above document will guide you out regarding the changes that has happened in iOS technology.

UIKIT Framework

  • In iOS 5.1, the UISplitViewController class adopts the sliding presentation style when presenting the left view (previously seen only in Mail). This style is used when presentation is initiated either by the existing bar button item provided by the delegate methods or by a swipe gesture within the right view. No additional API adoption is required to obtain this behavior, and all existing APIs—including that of the UIPopoverController instance provided by the delegate—will continue to work as before. If the gesture would be insupportable in your app, setting the presentsWithGesture property of your split view controller to NO disables the gesture. However, disabling the gesture is discouraged because its use preserves a consistent user experience across all apps.
  • In iOS 6, changes have been introduced so that you no longer need to set a delegate and implement a method for single-finger and single-tap gesture recognizers. This makes them work well with theUIControl objects.
  • In iOS 6 and later, the UIWebView class paints its contents asynchronously.
  • Autorotation is changing in iOS 6. In iOS 6, the shouldAutorotateToInterfaceOrientation: method of UIViewController is deprecated. In its place, you should use thesupportedInterfaceOrientationsForWindow: and shouldAutorotate methods.
    • More responsibility is moving to the app and the app delegate. Now, iOS containers (such as UINavigationController) do not consult their children to determine whether they should autorotate. By default, an app and a view controller’s supported interface orientations are set to UIInterfaceOrientationMaskAll for the iPad idiom andUIInterfaceOrientationMaskAllButUpsideDown for the iPhone idiom.
    • A view controller’s supported interface orientations can change over time—even an app’s supported interface orientations can change over time. The system asks the top-most full-screen view controller (typically the root view controller) for its supported interface orientations whenever the device rotates or whenever a view controller is presented with the full-screen modal presentation style. Moreover, the supported orientations are retrieved only if this view controller returns YES from its shouldAutorotate method. The system intersects the view controller’s supported orientations with the app’s supported orientations (as determined by the Info.plist file or the app delegate’s application:supportedInterfaceOrientationsForWindow: method) to determine whether to rotate.
    • The system determines whether an orientation is supported by intersecting the value returned by the app’s supportedInterfaceOrientationsForWindow: method with the value returned by thesupportedInterfaceOrientations method of the top-most full-screen controller.
    • The setStatusBarOrientation:animated: method is not deprecated outright. It now works only if the supportedInterfaceOrientations method of the top-most full-screen view controller returns 0. This makes the caller responsible for ensuring that the status bar orientation is consistent.
    • For compatibility, view controllers that still implement the shouldAutorotateToInterfaceOrientation: method do not get the new autorotation behaviors. (In other words, they do not fall back to using the app, app delegate, or Info.plist file to determine the supported orientations.) Instead, the shouldAutorotateToInterfaceOrientation: method is used to synthesize the information that would be returned by the supportedInterfaceOrientations method.
  • The willRotateToInterfaceOrientation:duration:,   willAnimateRotationToInterfaceOrientation:duration:, and didRotateFromInterfaceOrientation: methods are no longer called on any view controller that makes a full-screen presentation over itself—for example, presentViewController:animated:completion:.
    • You should make sure that your apps are not using these methods to manage the layout of any subviews. Instead, they should use the view controller’s viewWillLayoutSubviews method and adjust the layout using the view’s bounds rectangle.
  • In iOS 6, the viewWillUnload and viewDidUnload methods of UIViewController are now deprecated. If you were using these methods to release data, use the didReceiveMemoryWarning method instead. You can also use this method to release references to the view controller’s view if it is not being used. You would need to test that the view is not in a window before doing this.
  • It is not supported to set values for the shadowOffset or shadowColor properties of a UILabel object if its attributedText property contains a valid attributed string. Instead, use theNSShadowAttributeName attribute of the attributed string to set the shadow.
  • Due to compatibility concerns, the NSBaselineOffsetAttributeName attribute is no longer supported in iOS 6.
  • The NSTextAlignmentNatural value is not supported. It will throw an exception when it is used with the textAlignment property of UILabel or is supplied as the alignment parameter to thedrawInRect:withFont:lineBreakMode:alignment: method of NSString.
  • The setContentStretch: method of UIView has been deprecated. To achieve the same effect, use the resizableImageWithCapInsets: method of UIImage and display the image with aUIImageView.
  • The resizableImageWithCapInsets: method of UIImage effectively resizes images by tiling. As a performance optimization, it uses stretching rather than tiling when the user would not be able to tell the difference, such as when a single column or row is being stretched. But in certain circumstances, the user might want to actually stretch some region of an image. In iOS 6, theresizableImageWithCapInsets:resizingMode: method allows the caller to specify a tiling or stretching resizing mode.
  • The UICollectionViewLayout class has changed:
    • The class now supports the customization of the animations created during rotation. The names of methods for customizing insert and delete animations have also changed, so the same hooks can be used for rotations as well as for insertions and deletions.
    • The class has changed some method names. Specifically, decoration views are no longer referred to by “reuse identifier” but rather by “element kind.” Apps that are using decoration views will need to modify their code and be rebuilt to accommodate this.
  • The bottom edge of a UILabel view is now different from its baseline.

Previously, Auto Layout was interpreting the bottom of a UILabel to be the same as its baseline. While convenient in many cases, it caused problems if you wanted to place the top edge of one label against the bottom edge of another. In such a scenario, the bottom label would overlap the top one, and descenders from the top label could crash into ascenders from the bottom label. Now, Auto Layout interprets UILayoutAttributeBottom as the bottom of the text box (presuming the label is not bigger than its intrinsic content size) and UILayoutAttributeBaseline as the baseline of the text. If you have already created code for laying out labels according to the bottom or center point, your text will move around a little and you will need to adjust your constraints.

  • Apps with table views in their nib or storyboard files, and that were built using previous versions of iOS 6 beta, will require a clean build with beta 3 and newer.

Landscape-only apps that invoke a portrait-only view controller (such as the Game Center login screen) will cause the app to crash.

Workaround:

1.    Apps should provide the delegate method application:supportedIntefaceOrientationsForWindow and ensure that portrait is one of the returned mask values.

2.    When a UINavigationController is involved, subclass the UINavigationController and overriding supportedInterfaceOrientations.

Passbook

  • Passes will no longer fall back to background.png if strip.png is not included in your pass bundle.
  • The contents of the userInfo dictionary for PKPassLibraryDidChangeNotification have changed in the case of removed passes. Please consult the latest documentation for the new userInfo dictionary.
  • Passes must include the WWDR Intermediate Certificate in their signature. Passes that omit this certificate are invalid and cannot be added to Passbook. This restriction was not enforced in previous beta releases.
  • Images included in passes that use RGB need to include an alpha channel.

Simulator

  • No privacy alerts are displayed in iOS Simulator for apps that access Photos, Contacts, Calendar, and Reminders.
  • For this release, iOS Simulator does not support testing In-App Purchase. Please use a device to test your apps that use this feature.
  • When attempting to play an MP3 sound in Simulator, you will hear a popping sound instead.

Shared Photo Stream

  • The Shared Photo Stream feature is set to OFF when updating from iOS 6 beta 1 to a later release. The default setting should be ON.

     

     

UIRefreshControl in iOS6

 

All our clients want to have a basic functionality when its regarding the data display in the table view and that is having a spinner at it’s top. To do this you have the EGORefreshDemo that is available and is a little bit tricky to handle but is quite cool. 

In iOS 6 apple has been a little open hearted to provide you with a class named UIRefreshControl which is similar in fashion, so in this post we will have a look at the UIRefreshControl and will use it with a table view.
Step 1: Open you Xcode 4.5 and create an empty view based project and add a UITableViewController file to it that will have a list of various products. After you have done this then add your table view controller view in the app delegate and the run your project to see if you have got things right.
Step 2: After completing step no1 select your tableviewcontroller.h file and declare a global object of UIRefreshControl. 

Note: This class requires a call back method that will get triggered once you pull it so in simple terms we need a function, which we will assign to the UIRefreshControl and this function will be called when we pull our table to refresh it.

So now in your table view controller.h file you will be doing two things:
1. Creating a global object of the UIRefreshControl
2. Declaring a function that will be called when you pull the refresh control to refresh the table.
Step 3: Alright now after Step no 2 it’s time to switch to your tableviewcontroller.m file and select the view did load method where you will initialize the object of UIRefreshControl.
Code Explanation:I have used comments to make you understand the code.
After initializing the control it’s time to work on the callback method that would be associated with the UIRefreshControl.
Step 4: All set and done its time to run your project and see how it looks try pulling your table view and see apple’s new UIRefreshControl. Given below is the output for the same.
My Views on UIRefreshControl: After looking at this your client may or may not ask you to customize the UIRefreshControl class or stick with EGORefresh library, this class is available for iOS6 and not with any previous versions. But anyways its quite handly and less code is involved so it’s a good class by apple.
You may download the source code of this project from here.

Happy i coding

Create Horizontal UIPickerView (Custom)

So lets get started, first of all, all you need to do is drop a UIPickerView object on your view in the Interface Builder. Then in your .h file input:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UIPickerViewDelegate> {

IBOutlet UIPickerView *pickerView;

NSMutableArray *itemArray;

}

@property (nonatomic, retain)  UIPickerView *pickerView;

@end

Basically we’re just declaring our UIPickerView as IBOutlet (nothing new in declaration method here). We also added a NSMutableArray so that we can manipulate our items and be able to add our items in the pickerview easily later. We also add UIPickerViewDelegate at the interface because we will be using the built in Delegate functions of UIPickerView object.

Hang on a minute, what the heck is an NSMutableArray? If you are familiar with some basic programming I am sure that you are familiar with an array. An array is a defined quantity of collection of data. For eg:

myFish[14] holds 15 variables. from 0 to 14. (Remember index of an arrays always start with 0).
So you can access them by myFish[0] = Tetras; myFish[1] = Rasboras. And so on. But you are limited to 15 fishes. This is where NSMutableArray differs, an NSMutableArray is an array that is mutable, or expandable/changeable. So if you declare myFish as an NSMutableArray, then you can have up to whatever value you wish, so long as you be careful not to overload it (memory issues).

So now you have declared the UIPickerView, go to Interface Builder and connect BOTH the “delegate” and “Referencing Outlet” to the FileOwner.

Next, we go to .m file and synthesize the UIPickerView. Also we’d want to add the UIPickerView delegate methods as below (read the comments for each delegate’s purposes:

– (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {

return 1;

}

– (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {

return [itemArray count];

}


– (UIView *)pickerView:(UIPickerView *)thePickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view

{

return [itemArray objectAtIndex: row];

}

– (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {


}

numberOfComponentsInPickerView
This delegate is easy to implement, just type “return #;” where # is the number of components
you want. “Component” is the scrollable object in a pickerview. For example, a date pickerview has 3 components where user can select each of date, month and year. For our case, we are going to use just 1 component.

numberOfRowsInComponent
This delegate you need to return the number of items in each component. If you have multiple components,
you need to use switch (or if) statement to specify for each components. In our case we just have 1 component, so we only return the item count of our array.

viewForRow
This delegate is where you specify the “VIEW”/”Object” of the item. Since we store our items in
array, we just need to return the object by using: [itemArray objectAtIndex:row];

didSelectRow
This delegate is always called when user selects an item. Write the actions you’d like to happen when user select something in here.

Remember that delegate functions must be written as it is, EXACTLY. Any deviation might cause it not to work. Do check Apple docs for the latest delegate function names in case your implementation does not work.

Next is the fun part, customizing the UIPickerView. We will add the customization code in the viewDidLoad as we want it to be customized after the view is loaded. Write the codes below in the viewDidLoad.

// set the pickerview delegate to itself. This is important because if you don’t set

// this, then the delegate functions will not work/be called.

self.pickerView.delegate = self;

// here is where the customization lies: CGAffineTransform is a way to transform

// object according to scale and rotation. Here we rotate the pickerview by PI/2

// which is 90 degrees in radians. Then we concat the rotation transform with

// scale transform, and finally setting the pickerview transform.

CGAffineTransform rotate = CGAffineTransformMakeRotation(3.14/2);

rotate = CGAffineTransformScale(rotate, 0.1, 0.8);

[self.pickerView setTransform:rotate];

// set the center location.

self.pickerView.center = CGPointMake(160,75);

// Here I decided to add UILabel as the item’s “object”

// you can use ANYTHING here, like UIImageViews or any class of UIView

// Since we rotate the pickerview in one direction, we need to compensate

// the item’s angle by counter rotating it in the opposite direction,

// and adjust the scale as well. You may need to try a few times to get

// the right/suitable size as for the scale.

UILabel *theview[20];

CGAffineTransform rotateItem = CGAffineTransformMakeRotation(-3.14/2);

rotateItem = CGAffineTransformScale(rotateItem, 1, 10);

// next alloc and create the views in a loop. here I decided to have 20

// UIlabels, each with a text of 1 to 20. Set the other UIlabel’s property as you wish.

for (int i=1;i<=20;i++) {

theview[i] = [[UILabel alloc] init];

theview[i].text = [NSString stringWithFormat:@”%d”,i];

theview[i].textColor = [UIColor blackColor];

theview[i].frame = CGRectMake(0,0, 100, 100);

theview[i].backgroundColor = [UIColor clearColor];

theview[i].textAlignment = UITextAlignmentCenter;

theview[i].shadowColor = [UIColor whiteColor];

theview[i].shadowOffset = CGSizeMake(-1,-1);

theview[i].adjustsFontSizeToFitWidth = YES;

UIFont *myFont = [UIFont fontWithName:@”Georgia” size:15];

[theview[i] setFont:myFont];

theview[i].transform = rotateItem;

}


// then we initialize and create our NSMutableArray, and add all 20 UIlabel views

// that we just created above into the array using “addObject” method.

itemArray = [[NSMutableArray alloc] init];

for (int j=1;j<=20;j++) {


[itemArray addObject:theview[j]];

}

That is all there is to it. Run your app and it should display a nice horizontal UIPickerView!
How about have it do something when you select an item? Easy. Go back to .h and add another IBOutlet of UILabel *myLabel. Go to your XIB file in IB and add a label and connect the Outlet to FileOwner as myLabel. Goto .m file and synthesize myLabel. Then goto UIPickerView delegate called didSelectRow and add the following line:

  1. myLabel.text = [NSString stringWithFormat:@”SELECTED: %d”, row+1];

Now when you select a row, the label will show you which row you selected. Cool eh?

Happy iCoding

 

Post Image on friends facebook wall

Note: Remember one thing image is a file and if you want to post a file on your friends wall then in that case you have to make use of a class named “FBGraphFile”.

– (IBAction)postImageButtonclicked:(id)sender
{
if (fbgraphref!=nil)
{
NSMutableDictionary *variables = [[NSMutableDictionaryalloc]initWithCapacity:2];
FbGraphFile *fbfile = [[FbGraphFile alloc]initWithImage:imgv.image];
[variables setObject:fbfile forKey:@”file”];
[variables setObject:@”iPhone by radix” forKey:@”message”];
[fbgraphref doGraphPost:[NSStringstringWithFormat:@”%@/photos”,self.friendID] withPostVars:variables];
UIAlertView *objAlert = [[UIAlertView alloc]initWithTitle:@”Alert”message:@”Data Posted on friends wall” delegate:nil cancelButtonTitle:@”OK”otherButtonTitles:nil];
[objAlert show];
[self.navigationController popToRootViewControllerAnimated:YES];
}
}
Code Explanation: In the above code i am using the class FBGraphFile and storing the image data that i want to send to my friends wall.
Then with the help of dictionary i am encapsulating the image and some text about the image.
Later with the help of the FBGraph object i am posting the image and the text data regarding that image  with the help of the method named doGraphPost also make a note that this time its not the feeds that i am using its the photo variable since we want to push a photo on our friends wall.
Now when everything is in place you may run the application.
Now select a friend from the list and when you do you will be navigated to the following screen.
Now when you tap on the Post Image button then the image which is currently selected by you will be posted on your friends facebook feeds.
Later you may login to your facebook account and check your friends wall just in case to see if the image is loaded or not
You can download the source file from here.

Showing a Popover in iPad

The UIPopoverController class (for iPad) is a very neat way to present information to the user. In this blog, we’ll show how to use this class to present a popover view when the user touches a button. Let’s see how it works.

Start Xcode, click on “Create a new Xcode project,” and select the Single View Application template. Name the project PopoverDemo, and choose options as shown here:

Click Next, choose a location to save the project, and click Create.

We now have a single view application. Open ViewController.xib, and drag a UIButton to the view. Change its title to “Show Popover…” and also choose a color for the background of the view. When finished, the xib should look something like this:

In ViewController.h, make the following changes:

#import <UIKit/UIKit.h>
#import “PopoverViewController.h” 

@interface ViewController : UIViewController

@property (nonatomic, strong) IBOutlet UIButton *btnShowPopover;

– (IBAction)showPopover:(UIButton *)sender;

@end

Notice that we’ve imported a view controller that does not yet exist: we’ll take care of that soon. We’ve also added an IBOutlet property for the button, as well as an action method. Wire up the property and method (in the ViewController.xib file) as shown:

We will now make a new view controller for our popover. In the navigator panel, select ViewController.xib, then right – click, and choose “New File…” Select the Objective-C Class template, click Next, name the new class PopoverViewController, and make sure that it is a subclass of UIViewController as shown:

Click Next, save the class in the default location, and click Create.

Now open PopoverViewController.xib, select the view, and delete it. (You cannot resize a view made by Xcode as a part of the view controller creation process.) Drag a new UIView from the library, and in the Size inspector, set the view’s properties as shown:

(The value of Height will not be used, the height of the popover will be configured by the system when it is displayed.)

Drag a Navigation Bar to the top of the view; also drag a UILabel onto the view. Set their texts as shown:

In this demo, we’ve also set the background color for the view. Now right – click the File’s Owner object, and drag from the circle to the right of “view” to the new View we’ve just created. This sets the View in interface builder as the PopoverViewController’s view property. (If we omit this step, the view controller cannot display the view!)

Open ViewController.m, and alter the file as shown:

#import “ViewController.h” 

@interface ViewController ()
{
PopoverViewController *controller;
UIPopoverController *popoverController;
}

@end

@implementation ViewController

@synthesize btnShowPopover;

– (IBAction)showPopover:(UIButton *)sender
{
if ([popoverController isPopoverVisible]) {
[popoverController dismissPopoverAnimated:YES];
} else {
//the rectangle here is the frame of the object that presents the popover,
//in this case, the UIButton…
CGRect popRect = CGRectMake(self.btnShowPopover.frame.origin.x,
self.btnShowPopover.frame.origin.y,
self.btnShowPopover.frame.size.width,
self.btnShowPopover.frame.size.height);
[popoverController presentPopoverFromRect:popRect
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
}

– (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
controller = [[PopoverViewController alloc]initWithNibName:@”PopoverViewController” bundle:nil];
popoverController = [[UIPopoverController alloc]initWithContentViewController:controller];
}

– (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}

@end

Notice that the PopoverViewController (controller) and UIPopoverController (popoverController) objects are declared as iVars in the @interface section of the .m file, rather than properties. These iVars will not be exposed to any other class, nor should they be: they are private to the implementation of ViewController.

Let’s look first at viewDidLoad:. In this method, we instantiate both controller and popoverController. The controller object is an instance of our PopoverViewController class, we initialize it here with the nib name of the xib file, though initializing it with a nib name of nil would work as well. (Why? See the end of the blog for the answer…) After the controller is instantiated, we initialize popoverController with its contentViewController property set to the controller object.

In the showPopover: method, we respond to a touch on the button. If the popoverController is already shown, it is dismissed. Otherwise, we call presentPopoverFromRect: inView: permittedArrowDirections: animated:. The rectangle to use here is the frame of the object that summons the popover; in this case, the frame of the UIButton object. (This is the reason we set an outlet property to the button.) It is a good idea to use UIPopoverArrowDirectionAny as the value of the permittedArrowDirections argument: this ensures that wherever the system displays the popover, its arrow will always point to the control that summoned it.

In this demo, we’re not making any changes to the PopoverViewController class. We could place a button in the PopoverViewController.xib that calls a delegate method back to ViewController to dismiss the popover, but in this case, we simply rely on the fact that when the user touches outside the popover, it will be dismissed.

Run the application in both portrait and landscape mode:

There is nothing in our code that sets the behavior of the popover, except passing it the information about the button’s frame. In any orientation, the arrow of the popover will always point to the button, and the popover’s height and position will be adjusted to the best fit.

 

Unzipping Files In iOS Using ZipArchive

In this tutorial, I am going to demonstrate how you can zip and unzip files from within your iOS applications. We will be using a third party library called ZipArchive to achieve this. While there are a couple solutions out there to zip and unzip files, I feel that the ZipArchive library was the fastest and easiest way to get up and running.

Why Would I want To Unzip Files?

That’s a great question. There are a number of reasons why you might want to support zipping and unzipping files inside of your applications. Here are just a few:

Apple’s 50 MB App Store Download Cap

Apple has imposed a 50MB download limit over 3G on applications downloaded to appease carriers and not hog all of their bandwidth. One way to circumvent this is to keep your binaries very small, and download the resources your application needs. The best way to package these resources is of course, a zip file. So the process (as you will see demoed below), is to open your app, check for resource updates, download the zip file, and unzip it. Now you can ship smaller applications, that fetch their resources dynamically.

Dynamic Updates To Content

I touched on this above. When your application needs updated assets, the common practice is to submit an update to the App Store. This could take up to a week for Apple to Review and publish. A faster approach is to zip your assets up and stick them on a server somewhere (even your Dropbox) and have your app download and unzip them. This way, whenever you want to make asset-based changes to your application, you won’t need to submit another copy of it to the store.

Downloading Zip Files From The Web

One huge downfall of Safari and the Mail app is, they are unable to open zippedfiles. It would be nice to offer some sort of support to view zipped archives on your device. Many of the “download” apps in the store support this, and you can too with some help from ZipArchive.

Setting Up Your Project

Head over to http://code.google.com/p/ziparchive/ and checkout a copy of ZipArchive. Or you can just type this into your terminal.

svn checkout http://ziparchive.googlecode.com/svn/trunk/ziparchive-read-only

Once you have cloned the repository, delete the MakeFile file from the minizip folder. We will let XCode build our files. Now, drag this minizip folder as well as the ZipArchive.h and ZipArchive.mm files into your project, making sure to check “Create groups for any added folders”. Also, be sure your target is checked.

Note: No ARC Support

If you are using an ARC enabled project, you will need to tell the compiler not to use ARC for ZipArchive. To do this, click on the project in the left hand column. Then click on your target in the middle column and select the “Build Phases” tab.

Expand the “Compile Sources” area, locate ZipArchive.mm and double click on it. In the box that pops up, type in -fno-objc-arc and click Done.

Linking libz

The last step is to link your project against libz.1.2.5.dylib. From the Build Phases screen you navigated to above, expand the Link Binary With Librariessection and click the “+” button to add a new library. Search the list for libz.1.2.5.dylib, select it and click Add.

Now, compile your project and it should succeed with no errors. One thing to note is ZipArchive might produce some warnings, they are not a big deal, but if you are a warning Nazi (you should be), dig into the code and see if you can solve them yourself.

Downloading And Unzipping Files

I will now show you how easy it is to download a zip file from the web, unzip its contents, and use them in your project. The method of which we will download the files is very basic and most likely wouldn’t be used in production without further error reporting and checking.

The sample project has a view that looks like this:

It’s basically a UIImageView and a UILabel. Inside of the view controller I have set up IBOutlets for these two items. Make sure and download the sample project to see the implementation details. We will be downloading a zip file from the web that contains an image and a text file which you can see displayed in the screenshot above. Once unzipped, the image will be set as the viewable image in our UIImageView and the textual contents of the .txt file will be displayed inside of the UILabel.

**1. Import the ZipArchive headers **

#import "ZipArchive.h"

2. Download the the zip file

    // 1
    dispatch_queue_t queue = dispatch_get_global_queue(
                                                       DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSURL *url = [NSURL URLWithString:@"http://www.icodeblog.com/wp-content/uploads/2012/08/zipfile.zip"];
        NSError *error = nil;
        // 2
        NSData *data = [NSData dataWithContentsOfURL:url options:0 error:&error];

        if(!error)
        {
            // 3
            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
            NSString *path = [paths objectAtIndex:0];
            NSString *zipPath = [path stringByAppendingPathComponent:@"zipfile.zip"];

            [data writeToFile:zipPath options:0 error:&error];

            if(!error)
            {
                // TODO: Unzip
            }
            else
            {
                NSLog(@"Error saving file %@",error);
            }
        }
        else
        {
            NSLog(@"Error downloading zip file: %@", error);
        }

    });

This preliminary code downloads a zip file from iCodeBlog and saves it to the caches directory for the application.

  1. Creates a dispatch queue in which to run our code on with default priority.
  2. Quick and dirty way of fetching data from the web.
  3. Resolves the path to the caches directory and writes out the downloaded data to a local zip file

Now that you have it downloading the file to disk, it’s time to unzip that file and make use of it’s contents.

3. Unzipping the downloaded file

The last step here is to unzip the file you just downloaded. To be clear, it was save to the path /Library/Caches/zipfile.zip and once extracted, it’s contents will be inside of the Caches folder as well.

Replace the //TODO: Unzip in the code above, with the following code:

ZipArchive *za = [[ZipArchive alloc] init];
// 1
if ([za UnzipOpenFile: zipPath]) {
    // 2
    BOOL ret = [za UnzipFileTo: path overWrite: YES];
    if (NO == ret){} [za UnzipCloseFile];

    // 3
    NSString *imageFilePath = [path stringByAppendingPathComponent:@"photo.png"];
    NSString *textFilePath = [path stringByAppendingPathComponent:@"text.txt"];
    NSData *imageData = [NSData dataWithContentsOfFile:imageFilePath options:0 error:nil];
    UIImage *img = [UIImage imageWithData:imageData];
    NSString *textString = [NSString stringWithContentsOfFile:textFilePath
        encoding:NSASCIIStringEncoding error:nil];

    // 4
    dispatch_async(dispatch_get_main_queue(), ^{
        self.imageView.image = img;
        self.label.text = textString;
    });

Here is an explanation of what’s going on.

  1. Opens the file and unzips it in memory
  2. Writes the unzipped contents out to a given path (Caches folder)
  3. Makes use of the unzipped files
  4. Updates the UI (on the main thread of course) with the newly fetched data.

It really is that simple.

Zipping Files

Now you are going to see how to go the other way and zip up some files on disk. Again, this could be particularly handy when you want to allow your users to share groups of files via the web or email.

If you completed the steps above, your caches folder should have some files lying around that we can just zip up again and send off. We are going to zip up the two files you previously unzipped, stuff them into a new zip file, and write that out to the documents directory.

In my sample project, I have created a new button at the top that says “Zip Files” which links to an IBAction called zipFilesButtonPressed: when tapped. That is where I will be doing the zipping:

- (IBAction)zipFilesButtonPressed:(id)sender
{
    // 1
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docspath = [paths objectAtIndex:0];

    // 2
    paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *cachePath = [paths objectAtIndex:0];

    // 3
    NSString *zipFile = [docspath stringByAppendingPathComponent:@"newzipfile.zip"];       

    // 4
    ZipArchive *za = [[ZipArchive alloc] init];
    [za CreateZipFile2:zipFile];

    // 5
    NSString *imagePath = [cachePath stringByAppendingPathComponent:@"photo.png"];
    NSString *textPath = [cachePath stringByAppendingPathComponent:@"text.txt"];

    // 6
    [za addFileToZip:imagePath newname:@"NewPhotoName.png"];
    [za addFileToZip:textPath newname:@"NewTextName.txt"];

    // 7
    BOOL success = [za CloseZipFile2];
    NSLog(@"Zipped file with result %d",success);

}

Here is what’s going on:

  1. Resolve the path to the documents directory. We will need this when determining the path to write out our new zip file.
  2. Resolve the path to the caches directory. This is used to fetch the files that will be zipped up.
  3. Determines the path the zip file we will be writing out.
  4. Instantiates the ZipArchive object and tells it to create a new “in-memory” zip file. Note, the file won’t be written out until you call the corresponding CloseZipFile2 method.
  5. Resolve the path to the files that will be zipped up.
  6. Add the files to the zip archive. You can add as many files as you would like here. You can even add directories (ie you could have added the entire caches directory if you wanted to).
  7. Write out the zip file and close it. Just to test, we log the result to ensure that the zipping was successful.

After running through the application, tapping on the “Zip Files” button, look inside of the Application’s Documents folder (located ~/Library/Application Support/iPhone Simulator/[iOS Version]/Applications/[Unique ID]/Documents]. It should contain a single zip file called newzipfile.zip. If you unzip it, you should see the two files that you stuffed in there extracted.

Happy iCoding!

Download The Sample Project

 

Send Email With Attached Files from Iphone application


step 1 :

– add MessageUI framework

step 2 :

#import “MessageUI/MessageUI.h”

– add MFMailComposeViewControllerDelegate to .h file

step 3 :

– code in .m file on an clicked event of send Button

if ([MFMailComposeViewController canSendMail])

{

// csv file path details for attachments

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *filename =@”test.csv”;

NSString *fullPathToFile = [documentsDirectory stringByAppendingPathComponent:filename];

NSData *myData = [NSData dataWithContentsOfFile:fullPathToFile];

// pdf file path details for attachments

NSString *filename1 =@”NewPDF.pdf”;

NSString *pdfPath = [documentsDirectory stringByAppendingPathComponent:filename1];

NSData *myData1 = [NSData dataWithContentsOfFile:pdfPath];

MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];

mailer.mailComposeDelegateself;

NSMutableArray *arr = [[NSMutableArray alloc]init];

[arr addObject:emailText.text];

[mailer setToRecipients:arr];

[mailer setSubject:@”Vehicle Expenses from myConsultant”];

NSString *emailBody = @””;

[mailer setMessageBody:emailBody isHTML:NO];

[mailer addAttachmentData:myData mimeType:@”text/csv” fileName:filename];

[mailer addAttachmentData:myData1 mimeType:@”text/pdf” fileName:filename1];

[self presentModalViewController:mailer animated:YES];

[mailer release];

}

else

{

UIAlertView *alert = [[UIAlertView allocinitWithTitle:@”Failure”

message:@”Your device doesn’t support the composer sheet”

delegate:nil

cancelButtonTitle:@”OK”

otherButtonTitles:nil];

[alert show];

[alert release];

}

}

 

step 4 : // add delegate method anywhere in .m class file

– (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error

{

// Notifies users about errors associated with the interface

switch (result)

{

case MFMailComposeResultCancelled:

break;

case MFMailComposeResultSaved:

break;

case MFMailComposeResultSent:

break;

case MFMailComposeResultFailed:

break;

default:

{

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@”Email” message:@”Sending Failed – Unknown Error :-(”

delegate:self cancelButtonTitle:@”OK” otherButtonTitlesnil];

[alert show];

[alert release];

}

break;

}

[self dismissModalViewControllerAnimated:YES];

}

Only the thing is that you have a file available on a path you given for attachment

so enjoy Love coding, iCoding

 

Data Sharing on iCloud from iPhone/iPad with iOS 5.0

In Apple’s recent release iOS 5.0, major feature is iCloud service. iCloud is the service for sharing data of your application which is running in different devices. iCloud service can be use in application many different ways i.e. data sharing (where you can set values on key like for application NSUserDefaults), Document sharing and database sharing by using core data.
For iCloud integration, you must have Xcode 4.2 with iOS 5.0 device. You can not test this feature in iPhone/iPad Simulator.
Here is the some easier steps for data sharing : 

  1. Create application specific (i.e. com.your company.applicationname) apple id from Apple Developer Portal.
  2. Enable iCloud service for that App ID and create provisioning profile and install it on your mac.
  3. Create new project in Xcode with same app Id earlier created.
  4. Select target of application, click on summary and scroll down to Entitlement section. Click on custom entitlements.
  5. Above action will add “$ProjectName.Entitlement” file in your project. Add following keys in entitlement.
    com.apple.developer.ubiquity-container-identifiers as array
    com.apple.developer.ubiquity-kvstore-identifier as string
  6. Now add valur for key with $TeamID.com.yourcompany.applicationName. Don’t bother about TeamID. There are two ways to find Team ID. First, open provisioning profile into “TextEdit”, you will find as below image. You can also find Team Id from member center -> Account Info.
  7. Provisioning Profile

    Member Center

  8. That’s it from configuration side, Now you can add codeNSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *iCloudURL = [fileManager URLForUbiquityContainerIdentifier:@”$TeamID.com.yourcompany.applicationname”];
    NSLog(@”%@”, [iCloudURL absoluteString]);

    //iCloudURL == nil if iCloud is not supported or enable.

    if(iCloudURL){
    NSUbiquitousKeyValueStore *iCloudStore = [NSUbiquitousKeyValueStore defaultStore];
    [iCloudStore setString:@”Success” forKey:@”iCloudStatus”];
    [iCloudStore synchronize]; // For Synchronizing with iCloud Server
    NSLog(@”iCloud status : %@”, [iCloudStore stringForKey:@”iCloudStatus”]);
    }

  9. You can also verify data storage from iPhone Settings -> iCloud -> Storage & Backup -> Manage Storage. Also, In Mac -> System Preference -> iCloud -> Manage Storage.

 

Dropbox Integration in Iphone

Requirements:

1. You need the 4.0 version of the iPhone SDK. The version of your XCode should
be at least 3.2.3.
2. You need to have registered as a Dropbox application with mobile access at
http://dropbox.com/developers. You should have a consumer key and secret.
3. You need to download the dropbox sdk from https://www.dropbox.com/developers/releases

A. Adding DropboxSDK to your project

1. Open your project in XCode
2. Right-click on your project in the group tree in the left pane
3. Select Add -> Existing Files…
4. Navigate to where you uncompressed the Dropbox SDK and select the DropboxSDK
subfolder
5. Select “Copy items into destination group’s folder”
6. Make sure “Recursively create groups for any added folders” is selected
7. Press Add button
8. Find the Frameworks folder in your app’s group tree in the left pane
9. Make sure the framework Security.framework is added to your project
10. If not, right-click on Frameworks and select Add -> Existing Frameworks…
11. Select Security.framework from the list and select Add
12. Build your application. At this point you should have no build failures or
warning

B. Login successfully in your app

1. In your application delegate’s application:didFinishLaunchingWithOptions:
method, add the following code:

DBSession* dbSession = [[[DBSession alloc] initWithConsumerKey:@"<YOUR CONSUMER KEY>" consumerSecret:@"<YOUR CONSUMER SECRET>"] autorelease];
[DBSession setSharedSession:dbSession];

Note: you will need to #import “DropboxSDK.h” at the top of this file

2. Somewhere in your app, add an event to launch the login controller, which
should look something like this:

- (void)didPressLink {
DBLoginController* controller = [[DBLoginController new] autorelease];
[controller presentFromController:self];
}

Note: you will need to #import “DropboxSDK.h” at the top of this file

C. Creating folder in your dropbox using your App

1. In your .m file add the below code,

@interface DropBoxViewController () < DBLoginControllerDelegate, DBRestClientDelegate>

@property (nonatomic, readonly) DBRestClient* restClient;
@end
#pragma mark -
#pragma mark DBLoginControllerDelegate methods
- (void)loginControllerDidLogin:(DBLoginController*)controller
{
restClient = [self restClient];
[restClient setDelegate:self];
[def setBool:YES forKey:@"userLoggedToDropboxAccnt"];
[NSUserDefaults resetStandardUserDefaults];
[restClient loadMetadata:@"" withHash:photosHash];
}
- (void)loginControllerDidCancel:(DBLoginController*)controller {
}
- (DBRestClient*)restClient {
if (restClient == nil) {
restClient = [[DBRestClient alloc] initWithSession:[DBSession sharedSession]];
restClient.delegate = self;
}
return restClient;
}
#pragma mark -
#pragma mark DBRestClientDelegate methods
- (void)restClient:(DBRestClient*)client loadedMetadata:(DBMetadata*)metadata {
[photosHash release];
photosHash = [metadata.hash retain];
NSMutableArray* newPhotoPaths = [NSMutableArray new];
for (DBMetadata* child in metadata.contents) {
[newPhotoPaths addObject:child.path];
}
[photoPaths release];
photoPaths = newPhotoPaths;
self.contentArray = photoPaths;
if([photoPaths containsObject:folderNmTxtField.text]){
}
else{
[restClient createFolder:folderNmTxtField.text];
}
}

photosHash is of type NSString defined in .h file
photoPaths is an NSArray defined in .h file

D.Uploading file in yur dropbox using your app

if restClient not initialized earlier, add the below code

restClient=[self restClient];
[restClient setDelegate:self];
[restClient loadMetadata:@"" withHash:photosHash];

for uploading,

[restClient uploadFile: filename toPath: (folder in which file is to be uploaded) fromPath: (path of the file to be uploaded);

 

  • 1
  • 2

Need more help?

Hi there, was your problem or query resolved? If not & need more assistance, please do reach out to us at info@nanostuffs.com, we'll be more than delighted to help. Nanostuffs has 7+ years of extensive Salesforce & iOS/Android experience.
Holler Box