Thứ Ba, 31 tháng 3, 2015

iPhone 6C Rear Shell Leaked

iPhone-6c-Leaked-Flash

Today, an interesting leak appeared for the new cheaper iPhone model the iPhone 6C. While it is only a shell, the leak helps solidify the rumor that Apple will be releasing three new iPhone’s this year.  The images originated at future suppliers website and show the difference between the existing model and the prototype.

On the front you can tell that the camera flash cut out is no longer round and now more oblong. This could indicate that the iPhone 6C will have a two tone flash, however, the currently used two tone flash in the iPhone 6 is circular.

On the back you will notice that the speaker and microphone grills have changed. They both appear to have two rows instead of one.

iPhone-6c-Leaked-Speaker

Source : jailbreaknation[dot]com
post from sitemap

Thứ Hai, 30 tháng 3, 2015

Creating Your Own Custom Controls Using IBDesignable in Xcode 6

34 Flares 34 Flares ×

Have you tried to create a custom control in older versions of Xcode? It’s not that easy. What makes it so hard is that you couldn’t see your design in the Interface Builder. Every time you want to review the design changes, you can only test the control in the simulator. That’s troublesome. You would probably need to spend hours and hours on designing a single component.

With the release of Xcode 6, Apple introduced a new feature known as IBDesignable and IBInspectable for developers to build custom controls and allowed us to live preview the design right in the Interface Builder. Quite obviously, this is a huge productivity benefit.

In this tutorial, I will give you an introduction to IBDesignable and IBInspectable, and show you guys how to take advantage of the new feature. There is no better way to elaborate a feature than creating a demo. So we will build a custom interface called “Rainbow” together.

Rainbow

IBDesignable and IBInspectable

With IBDesignable and IBInspectable, developers are allowed to create interface (or view) that renders in Interface Builder in real time. In general, to apply this new feature, all you need to do is create a visual class by subclassing UIView or UIControl and then prefix the class name with @IBDesignable keyword in Swift. If you are using Objective-C, you use IB_DESIGNABLE macro instead. Here is a sample code in Swift:

1
2
3
@IBDesignable
class Rainbow: UIView {
}

In older versions of Xcode, you can edit the user-defined runtime attributes to change properties of an object (e.g. layer.cornerRadius) in Interface Builder. The problem is you have to key in the exact name of the properties. IBInspectable takes a step forward. When you prefix a property of the visual class with IBInspectable, the property will be exposed to the Interface Builder such that you can change its value in a much straightforward way:

Custom IBDesignable Control

Again if you are developing your app in Swift, what you have to do is just prefix your chosen property with the keyword @IBInspectable. Here is a sample code snippet:

1
2
3
 @IBInspectable var firstColor: UIColor = UIColor.blackColor() {
     // Update your UI when value changes
 }

Getting confused? No worries. You will understand what I mean after going through the project demo.

Building Your Xcode Project

Let’s get started by creating a new project in Xcode and choose Single View Application as a template, and name it RainbowDemo. We will use Swift in this project as the programming language, so don’t forget to choose it when creating the project.

Once finished, select the Main.storyboard in the Project Navigator and drag a View object from the Object Library to the View Controller. Change its color to #38334C (or whatever color you want) as well as set its size to 600 by 434. Then put it in the center of the main view. Don’t forget to change the color of the main view to the same color of the view object.

Tip: If you want to change the RGB Color values for your code, just open up your Color Palette and switch to the Sliders tab to alter the RGB values.
Demo1

With Xcode 6, you have to configure auto layout constraints for the view in order to support all types of iOS devices. Auto Layout is pretty powerful in the latest version of Xcode. For simple constraints, you can just click the Issues option of the Auto Layout menu and choose “Add Missing Contraints”, and Xcode will automatically configure the layout constraints for the view.

Demo2

Creating Custom View Class

Now that you’ve created the view in storyboard, it’s time to create our custom view class. We’ll use the Swift class template for the class creation. Name it “Rainbow”.

swift-class-template

Then insert the following code in the class:

1
2
3
4
5
6
7
8
9
10
11
import UIKit

class Rainbow: UIView {
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
   
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
}

As mentioned before, the visual class is a subclass of UIView. In order to use our custom class in live rendering, we need to override both initializers as shown above. Next split the view by selecting the assistant editor:

assistant-editor

Once done, select the main storyboard in the assistant editor, so you can see what you are building in real time. Remember to change the class name of the view to “Rainbow” under the Identity inspector:

IBDesignable Demo App

Implementing IBDesignable Controls

The first step to enable a control for live rendering is to set the custom view as Designable by prefixing the class name with @IBDesignable:

1
2
3
4
@IBDesignable
class Rainbow: UIView {
    ...
}

It’s kinda simple as you can see. But this simple keyword would make your development much easier. Next, we will add a few properties for setting the colors of the circles. Insert these lines of code in the Rainbow class:

1
2
3
@IBInspectable var firstColor: UIColor = UIColor(red: (37.0/255.0), green: (252.0/255), blue: (244.0/255.0), alpha: 1.0)
@IBInspectable var secondColor: UIColor = UIColor(red: (171.0/255.0), green: (250.0/255), blue: (81.0/255.0), alpha: 1.0)
@IBInspectable var thirdColor: UIColor = UIColor(red: (238.0/255.0), green: (32.0/255), blue: (53.0/255.0), alpha: 1.0)

Here, we predefine each property with a default colour, and tell it to redraw the view each time a user changes its value. Most importantly, we prefix each property with the @IBInspectable keyword. If you go to the Attributes inspectable of the view, you should find these properties visually:

color-pickers

Cool, right? By indicating the properties as IBInspectable, you can edit them visually using color picker.

Okay let’s move to implement the main methods of the Rainbow class, which is used to draw a circle on the screen. Insert the following method in the class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func addOval(lineWidth: CGFloat, path: CGPathRef, strokeStart: CGFloat, strokeEnd: CGFloat, strokeColor: UIColor, fillColor: UIColor, shadowRadius: CGFloat, shadowOpacity: Float, shadowOffsset: CGSize) {
   
    let arc = CAShapeLayer()
    arc.lineWidth = lineWidth
    arc.path = path
    arc.strokeStart = strokeStart
    arc.strokeEnd = strokeEnd
    arc.strokeColor = strokeColor.CGColor
    arc.fillColor = fillColor.CGColor
    arc.shadowColor = UIColor.blackColor().CGColor
    arc.shadowRadius = shadowRadius
    arc.shadowOpacity = shadowOpacity
    arc.shadowOffset = shadowOffsset
    layer.addSublayer(arc)
}

To make the code clean and readable, we create a common method for drawing a full or half circle according to the parameters provided by the caller. It’s pretty straightforward to draw a circle or an arc using CAShapeLayer class. You can control the start and end of the stoke using the strokeStart and strokeEnd properties. By varying the value of stokeEnd between 0.0 and 1.0, you can draw a full or partial circle. The rest of the properties are just used to set the color of a stroke, shadow color, etc. You can check out the official documentation for details of all the properties available in CAShapeLayer.

Next, insert the following methods in the Rainbow class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
override func drawRect(rect: CGRect) {
    // Add ARCs
    self.addCirle(80, capRadius: 20, color: self.firstColor)
    self.addCirle(150, capRadius: 20, color: self.secondColor)
    self.addCirle(215, capRadius: 20, color: self.thirdColor)
}

func addCirle(arcRadius: CGFloat, capRadius: CGFloat, color: UIColor) {
    let X = CGRectGetMidX(self.bounds)
    let Y = CGRectGetMidY(self.bounds)
   
    // Bottom Oval
    let pathBottom = UIBezierPath(ovalInRect: CGRectMake((X - (arcRadius/2)), (Y - (arcRadius/2)), arcRadius, arcRadius)).CGPath
    self.addOval(20.0, path: pathBottom, strokeStart: 0, strokeEnd: 0.5, strokeColor: color, fillColor: UIColor.clearColor(), shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
   
    // Middle Cap
    let pathMiddle = UIBezierPath(ovalInRect: CGRectMake((X - (capRadius/2)) - (arcRadius/2), (Y - (capRadius/2)), capRadius, capRadius)).CGPath
    self.addOval(0.0, path: pathMiddle, strokeStart: 0, strokeEnd: 1.0, strokeColor: color, fillColor: color, shadowRadius: 5.0, shadowOpacity: 0.5, shadowOffsset: CGSizeZero)

    // Top Oval
    let pathTop = UIBezierPath(ovalInRect: CGRectMake((X - (arcRadius/2)), (Y - (arcRadius/2)), arcRadius, arcRadius)).CGPath
    self.addOval(20.0, path: pathTop, strokeStart: 0.5, strokeEnd: 1.0, strokeColor: color, fillColor: UIColor.clearColor(), shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
   
}

The default implementation of the drawRect method does nothing. In order to draw circles in the view, we override the method to implement our own drawing code. The addCircle method takes in three parameters: arcRadius, capRadius and color. The arcRadius is the radius of the circle, while the capRadius is the radius of the rounded cap.

The addCircle method makes use of UIBezierPath to draw the arcs and it works like this:

  1. First it draws a half circle at the bottom
  2. Next it draws a full small circle at the edge of the arc.
  3. Finally, it draws the other half of the circle

In the drawRect method, we call the addCircle method three times with different radius and color. This figure illustrates how the circles are drawn:

ibdesignable-circles
Tip: If you need more information about UIBezierPath, you can check out Apple’s official documentation.

With the IBInspectable properties, you are now free to change the color of each circle right in the Interface Builder without diving into the code:

Screen Shot 2015-03-15 at 2.31.40 PM

Obviously, you can further expose arcRadius as an IBInspectable property. I’ll leave it as an exercise for you.

ibdesignable-exercise

Summary

After going through this tutorial, I hope that you now understand how to use both IBDesignable and IBInspectable in Xcode 6. With the real-time preview in the Interface Builder, this new feature would allow you to create custom componenents in a more effcient way.

For your reference, you can download the complete Xcode project from here. As always, leave me comment and share your thought about the tutorial.

Source : appcoda[dot]com
post from sitemap

Thứ Sáu, 27 tháng 3, 2015

App Showcase #3: FindMoreInternships by Vin Lee

3 Flares 3 Flares ×

As you know, from time to time, we feature apps developed by our readers, in particular for those who released their very first app. Here comes to the third app showcase. This time we talked to Vin Lee, the app developer behind FindMoreInternships, an app that provides internship information for college and high school students.

Vin will share with us how he came up with the app idea, learned to code and built the app. I encourage you to check out FindMoreInternships especially you are a student. If you’re still considering whether you should learn iOS programming, I hope Vin’s story will inspire you to kick start your app development journey.

findmoreinternships

1. Tell me more about your background and your app. Was it your first app?

For the past 17 years, one way or another, I have been in IT and have been involved in everything in-between graphic design to web design to help desk to systems administration to systems engineering.

My first published app is called FindMoreInternships, and it is an extension of one of my websites, FindInternships.com. At least 95% of the internsips on FindMoreInternships, can’t be found on the website, that’s why the app has the word ‘more’ in it. The app also focuses on internships that are currently available. Once the internship deadline has passed, the internship is automatically removed from the app. Essentially the app is like an internship web browser.

findinternships

While this is my first published app via the Apple Store, I have many private apps that were either part of a tutorial or part of my own projects.

2. How did you come up with the idea? How long did it take to develop the app?

For years I have been toying with many ideas for my first published app. But it wasn’t until apple released iOS 7, that I really started to appreciate the value of table-based apps, and the possibilities in which I could make use of it. The free tabled-based tutorials on appcoda.com helped me decide that this was the direction that I wanted to go in. Eventually I realized, why not base my first app on my website.

It took about 100 hours over the course of 3 months to develop the app, and then another 50 hours in 30 days for all the updates.

3. Do you have any programming experience before developing the app? How did you learn iOS programming?

I started coding with HTML at an internship at NASA in the mid-1990’s. In college, a few years later, my major included programing, so I had to take classes like Visual Basic, C++, Java, etc. I developed a few programs in college for projects. Later I graduated with a degree in Computer Engineering, where I began my career in systems/network administration. Thanks to my internship/college background, I had many opportunities to utilize what I learned. Sometimes it was assisting web developers to isolate problems and/or implement a feature on their site. Other times, I used programing to perform a wide variety of actions on Windows servers. When Apple released the iPhone in 2007, between then and the summer of 2014, I purchased many books, watched hundreds of videos, and browsed through scores of iOS development sites, while completing personal or practice projects in between.

4. Do you use Swift or Objective-C to develop your app? (If you use Objective-C, do you have any plan to use Swift for your next release?)

My app is 99.99999% Swift. Up until the summer of 2014, everything I learned/read/practiced about developing an iOS app was in Objective-C. However, later in the fall, I decided to challenge myself to produce my first published app with Swift. I use a Parse database, so I have to use an Objective-C bridge header for the Parse framework because the frame work is in Objective-C. The reference in the header is just one line of code.

5. What are you going to do to promote your app?

Right now, I primarily use Twitter to promote the app. In the coming months, I plan to use Facebook and a few PR sites. So far the campaigns are coming along really well.

6. What were the most valuable lessons you learnt from AppCoda and its books?

I read a ton of information online and watched at least 100 hours of iOS web development videos. I also attended an iOS course at Thinkful.com. The most helpful material was AppCoda.com, the Beginning iOS 8 Programming with Swift eBook from AppCoda, and the AppCoda screencasts. Prior to the fall of 2014 I completed almost every tutorial from website, and read all the tutorials several times. When the book was released, I read the entire book and completed the tutorials as well. Some chapters I’ve read several times as well. I had forgotten about the screencasts initially, but when I remembered, I watched all those several times as well. They really help complete my understanding. I really appreciate the way the tutorials are structured. I like the available code that is always provided for the complete project. And the videos were like icing on the cake. The table based tutorials were my favorite on the website. That material helped the most with my learning. I also loved the fact that the book/screencasts walked you through an entire project. Most of the time I had no problems understanding the material, and I had very few questions. I think this was because everything was presented in a very easy to understand, step-by-step format. Honestly, I don’t think I would have a published app if it were not for AppCoda.com and the beginner’s guide, despite everything else I had used over the years.

7. Any advices for those who just started learning iOS programming?

My first advice would be to use appcoda.com first. Go through all the tutorials and get familiar with development. Second, be patient. Producing a quality app takes time, even if you have all day to work on it. Even after you complete the app, take your time with testing it and test it throughly. Third, purchase the Beginning iOS 8 Programming with Swift – Complete Package. Honestly I was a little hesitant to do this. I had already spent money at Thinkful.com and up until then, other than a book or two, everything else I was using was free. And while I valued appcoda.com, I was afraid the package would just reiterate what I already went over on their website. To my surprise it was not, and the knowledge I learned from the package really helped me finally publish my app. Fourth, table based apps are easier to create. So start there for your first app. And last, don’t give up. I started 7 years ago, and thanks to AppCoda I’m finally here. And even though I had a background in IT, I must admit this was still very challenging to me.

8. What’s your next plan?

Not sure yet. The summer application internship season is almost over. That’s usually the when things slow down. The app has already had 3 major updates since it’s release at the beginning of the year, and there are some minor updates that are needed. So I’ll probably finish those and start focusing on creating an equivalent Android app, as well as focus more on marketing the Apple app. Oh, and I will probably delve into the intermediate AppCoda book.

Are you interested in sharing your app development experience? Please leave us comment below or send us a message.

Source : appcoda[dot]com
post from sitemap

MSS Rumors: iOS 8.2 Jailbreak Coming Out In An Hour

gwOtWoA

Right now the Mobile Security Summit is taking place in Beijing where famous hackers Comex, P0sixninja, Pimskeks and Chronic will be speaking along with members of TiaG. Reddit and Twitter have gone wild with rumors of a jailbreak happening at 4pm Beijing Time which is 1 AM PST (around 40 mins after this post is published). The rumor was started over a Weibo chat with no sufficient evidence.

MMS Info

Mobile-Security-Summit-2015 (1)

Currently this rumor is on the top of r/Jailbreak on Reddit

Screen Shot 2015-03-27 at 12.15.44 AM

Source : jailbreaknation[dot]com
post from sitemap

Apple Rumored To Release an iPhone 6S, iPhone 6s Plus, and iPhone 6C

2015-iPhone-6c-and-6s-plus

Even though it is only March new rumors of the next generation phones have hit the web. According to DigiTimes Apple is planning on releasing three new phones the second half of this year.   You may have guessed the iPhone 6s and iPhone 6+ but the third one is more of a surprise. Apparently there will be an iPhone 6C featuring a 4 inch display

All of the devices will come equipped with Corning Gorilla Glass, the sources said, adding the 6S series will use A9 chips and the 6C A8 chips. All of the devices will come equipped with NFC and fingerprint scanning technologies.

As you can see on the chart below, the iPhone 6C would be quite a bit smaller than the 6S / 6S Plus granted they stay the same size. Apple would most likely do this to appeal to the market that liked the smaller phones that they used to offer or who want a phone at a cheaper price.

iphone-6-size-comparison-100437672-primary.idge

Source : jailbreaknation[dot]com
post from sitemap

See the Year a Song was Released from iTunes Radio

iTunes Radio Music The next time you’re listening to iTunes Radio and you find yourself wondering which wonderful decade a particular song came from, wonder no more, because iTunes Radio can tell you when a song was released.

You can even see the date of a songs release with songs listed in iTunes Radio history, here’s all you need to do from the Music app on your iPhone or iPad:

  1. With the song playing in iTunes Radio, tap the (i) button at the top of the Music app
  2. Locate the songs release date at the bottom

Sometimes two dates are displayed, like in the example screenshot here, which is the original release date of the song, plus the date of the re-release.

Find what year a song was released in iTunes Radio

This is generally quite accurate, though if you’re getting information about a song that is from a Best Of list or Greatest Hits album, you’ll find the release date is sometimes listed as when that album was released rather than the original song, that’s really the only potential catch.

While you’re in that settings panel you can also tune the iTunes Radio station to play hits or discovery, and to include explicit lyrics or not, that latter tip is quite helpful because excluding explicit lyrics often impacts what versions of songs are played, with the explicit toggle on you’ll be more likely to find album versions of a song playing versus a clean radio version – sometimes a single word or lyric can make that difference.

This is helpful for obvious reasons, but it’s also useful to settle the debate about what year was the greatest ever for music, or just knowing when a song was actually put out.

Source : osxdaily[dot]com
post from sitemap

Thứ Năm, 26 tháng 3, 2015

Asia Unites Against Poaching

Representatives from 13 Asian countries committed to immediate action to stamp out poaching at the conclusion of a four-day symposium hosted by the Nepal government in Kathmandu from February 2-6, 2015.

The Symposium: Towards Zero Poaching in Asia adopted five recommendations:

  • Swift and decisive action to elevate the importance and effectiveness of antipoaching initiatives and cooperation among all relevant ministries, departments and agencies within their borders, while at the same time strengthening international cooperation in the face of this serious criminal activity.
  • Adoption of the Zero Poaching Tool Kit and assessment of current antipoaching responses to determine improvements and close serious gaps.
  • Increase and improve collaboration as a successful antipoaching response is critically dependant on effectively engaging a diverse number of shareholders
  • Improve standards, training and support for rangers, other frontline staff and prosecutors.
  • Commit to identifying a Zero Poaching national contact point to effectively coordinate transboundary efforts to stop poaching.

Tika Ram Adhikari, Director General of Nepal’s Department of Wildlife Conservation and Soil Conservation, said: “Nepal was proud to host this vital conversation in Asia because we recognize that poaching is robbing us of our wildlife wealth, which includes tigers, rhinos and elephants. We cannot allow wildlife crime to continue to wrap its tentacles deeper into the region. Our individual efforts may win us a few battles, but we can only win the war if Asia presents a united front to stop the poaching, end the trafficking and wipe out demand.”

Mike Baltzer, Leader, WWF Tigers Alive Initiative, said: “This is the beginning of the end for poaching across Asia. WWF is proud to have supported this landmark meeting and is committed to be part of the new determined movement for Zero Poaching in Asia.”

Nepal was the natural host for the symposium having achieved zero poaching for two years in the past four years. At the symposium, representatives from local communities, protected areas as well as enforcement agencies shared their lessons lea

At the closing ceremony, Nepal’s legendary Chitwan National Park (CNP) also became the first global site to be accredited as Conservation Assured Tiger Standard (CA|TS).Despite the threats that CNP faces, the protected area has seen an increasingly effective management and protection regime. This further demonstrates the commitment of Nepal towards zero poaching.

Thirteen Asian countries participated in the symposium: Bangladesh, Cambodia, China, Viet Nam, Malaysia, Russia, Indonesia, Myanmar, Thailand, Nepal, India, Bhutan, and Lao PDR. Partner NGOs and other organisations included IUCN, TRAFFIC, CITES, UN Office on Drugs and Crime, US Department of Justice, SMART Partnership and Southern African Wildlife College.

WWF co-hosted the symposium with Global Tiger Forum, National Trust for Nature Conservation and the South Asian Wildlife Enforcement Network.

The symposium provides valuable direction on tackling poaching in advance of the Kasane Conference on the Illegal Wildlife Trade to be hosted by the Botswana government on 25th March 2015. This meeting follows the London Conference on the Illegal Wildlife Trade hosted by the UK government in February 2014, where 41 governments committed to taking “decisive and urgent action….” through the agreed declaration.

Thứ Tư, 25 tháng 3, 2015

iOS 8.3 Beta 4 Released, New Version & Possibly Jailbreak Coming Soon

83update

Even though Apple just recently released iOS 8.2 to go public a new firmware has been receiving a great deal of attention. Today, iOS 8.3 beta 4 was released to developers indicating that it could be going public in the near future. iOS versions usually have a great effect on when jailbreaks are released and it is most likely that nothing new will come out until 8.3 has gone public.

iOS 8.3 will offer many new features including CarPlay support, a whole new customization emoji system,  and expansions to previous features like Apple Pay. If you are a developer you can download it now via the dev center or an OTA on a device running iOS 8.3

iOS-83-beta-4-dev-center

Source : jailbreaknation[dot]com
post from sitemap

iOS 8.3 Beta 4 Released to Developers & Public Beta Users for Testing

iOS 8

Apple has released the fourth beta release of iOS 8.3 to those registered with the iOS developer program, or who are participating in the iOS Public Beta. The build is versioned as 12F5061 and is available now for compatible iPhone, iPad, and iPod touch devices.


The simplest way to install iOS 8.3 beta 4 is through the Over-the-Air software update mechanism on the iOS device. This is accessible through Settings > General > Software Update. As always, back up the device before updating system software, this is particularly important when that iOS software is a beta version. Additionally, it is not advised to run beta software on a primary device.

iOS 8.3 beta install

The new beta build IPSW can also be downloaded from the iOS Dev Center for those registered with Apple.

iOS 8.3 continues to focus on improvements, bug fixes, and feature enhancements, and the version is expected to include new diverse Emoji icons, wireless CarPlay connectivity, Apple Pay improvements, new languages for Siri, and Google 2-factor authentication support.

While this is the fourth beta of iOS 8.3 overall, this is the second release available to Public Beta users of iOS. There is no known timeline for iOS 8.3 being released to the general public, but one could reasonably expect a final version to arrive before Apple Watch debuts.

Separately, Apple has also made Xcode 6.3 beta 4 available to iOS developers.

Source : osxdaily[dot]com
post from sitemap

Thứ Hai, 23 tháng 3, 2015

Layout: Instagram’s New Collage App

UWIpFk6

Today Instagram released a new app to create collages named layout. The app is supplemental to the popular photo social networking service owned by Faceboook. Last year, the company produced Hyperlapse which allowed people to take high quality time lapses on their phones. Layout is another app which uses Instagram at its core but adds new functionality for anyone that wants to download the separate app. It makes sense that Instagram would create a collage app as the App Store has been flooded with 3rd party alternatives.

The app can also detect which of your photos have faces in them in case you want to avoid food / object only content.

 

Instagram Layout highlights:

  • Re-mix up to 9 of your photos at a time to create fun, personalized layouts.
  • Use the Faces tab to quickly find photos with people in them.
  • Capture the moment in Photo Booth mode with quick, spontaneous shots.
  • Save your layouts to your camera roll and share them seamlessly to Instagram or other networks.
  • Easily see the last 30 photos you’ve selected in the Recents tab.
  • Pair your layouts with Instagram’s filters and creative tools afterwards to make them stand out even more.
  • Download and start creating immediately. No signup or account required—and no clutter breaking up your flow.
Source : jailbreaknation[dot]com
post from sitemap

Introduction to Custom View Controller Transitions and Animations

8 Flares 8 Flares ×

Looking at the built in apps from Apple on your iOS device, you will notice the various animated transitions as you move from one view to another for example the way view controllers are presented in master-detail views with a swipe that slides the detail view controller over the master view controller as seen in the Messages app or Settings app and the various transitions that represent a segue to another view controller.

iOS 7 introduced custom view controller transitions which make it possible for developers to create their own animated transitions from one view controller to the next in their apps. In this tutorial, we’ll take a look at how to do this. We’ll also look at how to create gesture driven transitions called interactive transitions. To follow along, download the starter project which we’ll be using throughout the tutorial.

custom-view-transition

Getting Started

To create custom transitions you have to follow three steps:

  • Create a class that implements the UIViewControllerAnimatedTransitioning protocol. Here you will write code that performs the animation. This class is referred to as the animation controller.
  • Before presenting a view controller, set a class as its transitioning delegate. The delegate will get a callback for the animation controller to be used when presenting the view controller.
  • Implement the callback method to return an instance of the animation controller from the first step.

Run the starter project and you will be presented with a table view of a list of items. There is an Action button on the navigation bar and when you tap it you’ll be presented with another view that appears in the usual modal style of sliding up from the bottom. We will write a custom transition for this view.

custom view controller animation

Custom Present Transition

The first thing to do as stated previously, is to create the animation controller. Create a new class called CustomPresentAnimationController and make it a subclass of NSObject. Change its declaration as shown.

1
class CustomPresentAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

UIViewControllerAnimatedTransitioning protocol has two required methods which we’ll add next. Add the following methods to the class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
    return 2.5
}
   
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
       
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
    let containerView = transitionContext.containerView()
    let bounds = UIScreen.mainScreen().bounds
    toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.size.height)
    containerView.addSubview(toViewController.view)
       
    UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .CurveLinear, animations: {
        fromViewController.view.alpha = 0.5
        toViewController.view.frame = finalFrameForVC
        }, completion: {
            finished in
            transitionContext.completeTransition(true)
            fromViewController.view.alpha = 1.0
    })
}

The first method specifies the length of the transition animation. For the demo app we’ve set it at 2.5 seconds, but you probably should set it to a smaller number in a real app.

In the second method we use the transitionContext to get the view controller we are navigating from, to, the final frame the transition context should have after the animation completes and the container view which houses the views corresponding to the to and from view controllers.

We then position the to view just below the bottom of the screen. Then we add the to view to the container view and in the animate closure, we animate the to view by setting its final frame to the location given by the transition context. We also animate the from view‘s alpha value so that as the to view is sliding up the screen over the from view, the from view will be faded out. The duration of the animation used is the one set in transitionDuration(transitionContext:). In the completion closure, we notify the transition context when the animation completes and then change the from view‘s alpha back to normal. The framework will then remove the from view from the container.

With the animation controller completed, we need to link it to a storyboard segue.

Open the ItemsTableViewController.swift file and change the class declaration as shown.

1
class ItemsTableViewController: UITableViewController, UIViewControllerTransitioningDelegate {

UIViewController has a property named transitionDelegate that supports custom transitions. When transitioning to a view controller, the framework checks this property to see if a custom transition should be used. UIViewControllerTransitioningDelegate supplies custom transitions.

Open Main.storyboard and select the Present modally segue to Action View Controller and in the Attributes Inspector, set its Identifier to showAction.

Custom View Controller Animation

Back in ItemsTableViewController add the following to the class.

1
2
3
4
5
6
7
8
9
let customPresentAnimationController = CustomPresentAnimationController()

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
       
    if segue.identifier == "showAction" {
        let toViewController = segue.destinationViewController as UIViewController
        toViewController.transitioningDelegate = self
    }
}

Here we create an instance of our animation controller and then in the prepareForSegue() function, we detect the segue for the Action screen and set the transitionDelegate property of the destination view controller.

Add the following UIViewControllerTransitioningDelegate method to the class. This returns the instance of our custom animation controller.

1
2
3
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return customPresentAnimationController
}

Run the application and you should see the Action view slide up slowly from the screen and bounce a little before settling.

Custom View Controller Animation #3

If you want a slightly different effect, then change this statement in CustomPresentAnimationController.swift

1
toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.size.height)

to the statement below, which changes the original position of the to view controller to be above the screen.

1
toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, -bounds.size.height)

Run the app and the Action view should fall from above.

Custom View Controller

Custom Dismiss Transition

We’ve set a custom transition for presenting our view, but when it is dismissed, it uses the default transition set by Apple.

Custom View Controller #4

The UIViewControllerTransitioningDelegate also allows you to specify an animation controller to use when dismissing a view controller as well as when presenting one. We’ll create this next.

Create a class named CustomDismissAnimationController that is a subclass of NSObject. Modify its declaration as shown.

1
class CustomDismissAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

Add the following to the class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
    return 2
}

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
    let containerView = transitionContext.containerView()
    toViewController.view.frame = finalFrameForVC
    toViewController.view.alpha = 0.5
    containerView.addSubview(toViewController.view)
    containerView.sendSubviewToBack(toViewController.view)
   
    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
        fromViewController.view.frame = CGRectInset(fromViewController.view.frame, fromViewController.view.frame.size.width / 2, fromViewController.view.frame.size.height / 2)
        toViewController.view.alpha = 1.0
    }, completion: {
        finished in
        transitionContext.completeTransition(true)
    })
}

This is similar to the implementation of the presentation transition. In the animateTransition() function, we get the to and from view controllers. The to view controller here is the table view controller. We change its view’s alpha value so that it will start off as being faded when we start animating. We then add the view to the container and place it behind the from view controller’s view so that it won’t be visible just yet.

In the animation block, we animate the from view‘s size to have a width and height of 0, maintaining its center. This will have an effect of shrinking the from view to nothingness. We also animate the to view‘s alpha to being completely visible.

In ItemsTableViewController add the following property.

1
let customDismissAnimationController = CustomDismissAnimationController()

Add the following function to the class.

1
2
3
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return customDismissAnimationController
}

The UIViewControllerTransitioningDelegate protocol provides the above function which retrieves the animation controller of a dismissed view controller.

Run the app. You should see the following animation.

Custom View Animation #5

The animation isn’t what we expected. You can see the white frame of the from view shrinks as expected, but the image on the view doesn’t change in size. This is because changing the view’s frame doesn’t affect its children. We’ll fix this by using UIView snapshotting.

UIView snapshotting works by taking a snapshot of an existing UIView and rendering it into a lightweight UIView. We will then use this snapshot in out animation and not the actual view.

Replace the animateTransition() function with the following.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
    let containerView = transitionContext.containerView()
    toViewController.view.frame = finalFrameForVC
    toViewController.view.alpha = 0.5
    containerView.addSubview(toViewController.view)
    containerView.sendSubviewToBack(toViewController.view)
       
    let snapshotView = fromViewController.view.snapshotViewAfterScreenUpdates(false)
    snapshotView.frame = fromViewController.view.frame
    containerView.addSubview(snapshotView)
       
    fromViewController.view.removeFromSuperview()
       
    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
        snapshotView.frame = CGRectInset(fromViewController.view.frame, fromViewController.view.frame.size.width / 2, fromViewController.view.frame.size.height / 2)
        toViewController.view.alpha = 1.0
    }, completion: {
        finished in
        snapshotView.removeFromSuperview()
        transitionContext.completeTransition(true)
    })  
}

Here, we create a snapshot of the from view controller‘s view, add it to the container and remove the from view from the container. We then shrink this snapshot in our animation and when the animation completes, we remove the snapshot view from the container.

Run it and the animation should now run smoothly.

Custom View Controller Animation

Navigation controller transitions

We’ve looked at adding a custom transition for modal view controller presentation where we added a transitioning delegate to the presenting view controller. However, setting a delegate on every view controller can get tiresome when working with a UITabBarController or UINavigationController.

These controllers give a simpler approach whereby the animation controller for a transition is supplied via the UITabBarControllerDelegate or UINavigationControllerDelegate.

We’ll see this in action by adding a custom transition to a navigation controller.

To start off, we create an animation controller. Create a class called CustomNavigationAnimationController, make it a subclass of NSObject and change its declaration as follows.

1
class CustomNavigationAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

Add the following to the class. I use a simplified version of this cube animation for this animation controller. The animation controller is set up as usual just like we’ve seen with the previous two animation controllers. Notice the reverse class variable. We use this to determine the direction of the animation, depending on whether we are moving from master to detail view or vice versa.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
var reverse: Bool = false
   
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
    return 1.5
}
   
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let containerView = transitionContext.containerView()
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toView = toViewController.view
    let fromView = fromViewController.view
    let direction: CGFloat = reverse ? -1 : 1
    let const: CGFloat = -0.005
       
    toView.layer.anchorPoint = CGPointMake(direction == 1 ? 0 : 1, 0.5)
    fromView.layer.anchorPoint = CGPointMake(direction == 1 ? 1 : 0, 0.5)
       
    var viewFromTransform: CATransform3D = CATransform3DMakeRotation(direction * CGFloat(M_PI_2), 0.0, 1.0, 0.0)
    var viewToTransform: CATransform3D = CATransform3DMakeRotation(-direction * CGFloat(M_PI_2), 0.0, 1.0, 0.0)
    viewFromTransform.m34 = const
    viewToTransform.m34 = const
       
    containerView.transform = CGAffineTransformMakeTranslation(direction * containerView.frame.size.width / 2.0, 0)
    toView.layer.transform = viewToTransform
    containerView.addSubview(toView)
       
    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
        containerView.transform = CGAffineTransformMakeTranslation(-direction * containerView.frame.size.width / 2.0, 0)
        fromView.layer.transform = viewFromTransform
        toView.layer.transform = CATransform3DIdentity
    }, completion: {
        finished in
        containerView.transform = CGAffineTransformIdentity
        fromView.layer.transform = CATransform3DIdentity
        toView.layer.transform = CATransform3DIdentity
        fromView.layer.anchorPoint = CGPointMake(0.5, 0.5)
        toView.layer.anchorPoint = CGPointMake(0.5, 0.5)
   
        if (transitionContext.transitionWasCancelled()) {
            toView.removeFromSuperview()
        } else {
            fromView.removeFromSuperview()
        }
        transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
    })        
}

Open ItemsTableViewController.swift and modify the class declaration as follows.

1
class ItemsTableViewController: UITableViewController, UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {

UINavigationControllerDelegate supplies the animation controller.

Add the following property to the class.

1
let customNavigationAnimationController = CustomNavigationAnimationController()

Add the following at the end of viewDidLoad().

1
navigationController?.delegate = self

The above sets the host navigation controller’s delegate so that the new transition delegate methods can be received.

Then add the following to the class.

1
2
3
4
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    customNavigationAnimationController.reverse = operation == .Pop
    return customNavigationAnimationController
}

The above function is called to request for an animation controller to navigate between the from and to view controllers and it returns an instance of our animation controller. The direction of the transition is based on whether this is a push or pop navigation operation.

Run the app. Select a table view cell and you should see the animation below.

Custom View Animation #7

Making it Interactive

We’ll make the above transition interactive, i.e. the user will be able to control the transition with gestures.

iOS built-in apps come with this feature. As an alternative to the back button, you can initiate a transition by swiping from the left side of the screen. You can use a short swipe to briefly view the master view and then cancel the transition. A long swipe initiates the pop navigation operation.

Custom View Animation #8

To get started, we need an interaction controller. Interactive controllers use the UIViewControllerInteractiveTransitioning protocol. The navigation controller delegate or the transitioning delegate requests for an optional interaction controller after requesting an animation controller.

Let’s create the interaction controller. Create a new class and name it CustomInteractionController and make it a subclass of UIPercentDrivenInteractiveTransition.

UIPercentDrivenInteractiveTransition implements the UIViewControllerInteractiveTransitioning protocol so we wont have to add that to our class.

To use UIPercentDrivenInteractiveTransition, your animation controller must use a single UIView animation, so that the animation will be able to be stopped, reversed and played.

Add the following to the class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
var navigationController: UINavigationController!
var shouldCompleteTransition = false
var transitionInProgress = false
var completionSeed: CGFloat {
    return 1 - percentComplete
}
   
func attachToViewController(viewController: UIViewController) {
    navigationController = viewController.navigationController
    setupGestureRecognizer(viewController.view)
}
   
private func setupGestureRecognizer(view: UIView) {
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "handlePanGesture:"))
}
   
func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) {
    let viewTranslation = gestureRecognizer.translationInView(gestureRecognizer.view!.superview!)
    switch gestureRecognizer.state {
    case .Began:
        transitionInProgress = true
        navigationController.popViewControllerAnimated(true)
    case .Changed:
        var const = CGFloat(fminf(fmaxf(Float(viewTranslation.x / 200.0), 0.0), 1.0))
        shouldCompleteTransition = const > 0.5
        updateInteractiveTransition(const)
    case .Cancelled, .Ended:
        transitionInProgress = false
        if !shouldCompleteTransition || gestureRecognizer.state == .Cancelled {
            cancelInteractiveTransition()
        } else {
            finishInteractiveTransition()
        }
    default:
        println("Swift switch must be exhaustive, thus the default")
    }
}

The attachToViewController() method is passed a reference of the navigation controller which it uses to initiate a pop transition when a gesture occurs. We then set up a gesture recognizer, which will call the handlePanGesture() method when a swipe is made. This checks the gesture recognizer state and does the following at each stage:

  • Began: It sets transitionInProgress to true and initiates a pop navigation.
  • Changed: Here the gesture is in progress, so it determines the percentage of the transition. A 200 point swipe will cause the transition to be 100% complete. It then determines if the transition should complete depending on where the gesture finishes. Here we check if the user swiped to at least half the screen before releasing.
  • Cancelled/Ended: Sets the transitionInProgress to false and cancels the transition if shouldCompleteTransition was set to false or if the gesture was cancelled. Otherwise, the transition is completed.

We used a computed property to determine the completion speed. completionSeed is a UIPercentDrivenInteractiveTransition property that informs the framework how much of the animation remains when a gesture completes. A larger number will make the view controller snap back quicker if the interaction is cancelled.

To use our interaction controller, open ItemsTableViewController.swift and add the following to the class.

1
let customInteractionController = CustomInteractionController()

Add the following at the beginning of the navigationController(_:animationControllerForOperation:
fromViewController:toViewController:)
function.

1
2
3
if operation == .Push {
    customInteractionController.attachToViewController(toVC)
}

This calls the CustomInteractionController’s attachToViewController() method and passes it a reference of the to view controller when it detects a push navigation operation.

Then add the following to the class.

1
2
3
func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
    return customInteractionController.transitionInProgress ? customInteractionController : nil
}

After the framework asks for and gets an animation controller, it asks for an interaction controller using the method above. The above returns an instance of our interaction controller if a transition is in progress.

Run the app and you should see the transition shown.

Custom View Animation #9

Conclusion

We’ve looked at how to create custom view controller transitions and how to make a transition interactive. With these features, developers now have full control over the animations used in their application as it transitions from one view controller to the next and thus can build unique experiences to delight their users. You can download the completed project here.

Source : appcoda[dot]com
post from sitemap

Chủ Nhật, 22 tháng 3, 2015

How to Make Phone Calls from Mac Using iPhone

Making and Receiving Phone Calls from Mac with iPhone

If you have a Mac and an iPhone, you can now make phone calls from your Mac using that iPhone. The phone call will sound through the Mac speakers and use the Mac microphone, but the actual call itself routes through the iPhone. This is a part of the Continuity suite, which is really nice feature set in newer versions of iOS and OS X that allow for seamless transition between Macs and iPhones and iPads. Phone calling from the Mac is quite simple to use once you have it set up properly.

Requirements for Making Phone Calls from a Mac via iPhone

You do not need to have Bluetooth enabled to use this feature, but you must be on the same wi-fi network, the devices must be using the same iCloud account, and the feature must be enabled in OS X and iOS, both of which require a modern version to function (OS X 10.10.x or newer, and iOS 8.x or newer). This is basically the same set of requirements which is necessary for using HandOff, which is another Continuity feature.

How to Enable Phone Calls from Mac with iPhone

Before making phone calls from the iPhone using your Mac, you’ll need to enable the feature on both iPhone and OS X, this is easy:

  1. From the iPhone, open Settings and go to “FaceTime”
  2. Toggle the switch for “iPhone Cellular Calls” to the ON position, this may be turned off so be sure it is ON
  3. iPhone cellular calls setting

  4. From the Mac, open the “FaceTime” application and from the FaceTime menu, select “Preferences”
  5. Toggle the switch for “iPhone Cellular Calls” so that it is ON
  6. Enabling iPhone Cellular Calls on Mac

This is particularly important to double-check that settings are enabled and set properly because many users opted to turn off their Mac ringing with an inbound iPhone call after experiencing it once or a dozen times, which can be desired or annoying depending on the environment.

How to Make Phone Calls from the Mac Using the iPhone

Once configuration is complete and the devices are nearby on the same wireless network, making an outbound call from the Mac through an iPhone is really easy:

  1. Open the “Contacts” app on the Mac, and locate the personal or contact to make a call to
  2. Hover the cursor over the phone number in Contacts app to reveal a little phone icon, click on that phone icon to make the call

Making a Phone Call from Mac with iPhone

You’ll see a little notification like popup arrive in the top corner of the Mac screen as the call starts, you’ll have the option to mute and end calls using that screen, which remains active as long as the call is active.

Making a phone call from the Mac through an iPhone displays this window to interact with the call

You can also make phone calls from the Mac from the FaceTime app, though if you’re calling someone on another Mac or iPhone it is likely to get routed through the Apple VOIP FaceTime Audio protocol. Additionally, you can make phone calls from Safari by hovering over a number on the web.

Receiving Phone Calls from iPhone on the Mac

When calling is configured properly, you’ll also discover that the Mac will receive inbound calls as well. When an inbound call is coming through, a notification will display in OS X, the Mac will ring alongside the iPhone, and you can answer the call in OS X, which again will route through the Mac speaker and microphone (or a headset, if one is in use).

The Mac receiving a phone call from iPhone

While you can stop the Mac receiving calls, if you do so it will not be able to make calls too.

Can You Make Phone Calls from the Mac Without Receiving Them on the Mac?

At the moment there is no way to turn off the reception of phone calls on the Mac while maintaining the ability to make phone calls from the Mac, the only option is to change the ringtone on the Mac to a quiet or silent one. This is similar to other iPhones and iPads using the same Apple ID, where device ringing can be disabled too through iOS Settings but doing so will also remove the ability for the same device to make an outbound call.

Where is the Number Dialing Pad on the Mac for Making Calls?

Great question! Currently, OS X does not have a built-in dialing pad with numbers for making calls to new numbers. Hopefully that will change in the future, but for the time being, you’ll need to turn to the iPhone if you need to use a numerical dialing pad on the call.

If you like the ability to make and receive calls on the Mac, you’ll probably also like to be able to make and receive text messages from Mac OS X too, which can be setup with these instructions.

Source : osxdaily[dot]com
post from sitemap

Thứ Bảy, 21 tháng 3, 2015

How to Mark All iMessages as Read on iPhone & iPad Instantly

New Unread Messages badge

We’ve all experienced it, a huge number of texts and iMessages arriving on our iPhone or iPad, that you either know aren’t important or you already read on another devices Messages app. Or maybe the messages are coming from someone you’d just prefer to ignore, whatever the case, you can instantly mark all messages as read in iOS using a quick little known trick.


This is significantly faster than manually opening each individual thread, tapping back to the primary messages window, then repeating the same with each unread conversation to mark them manually.

Instantly Mark All iMessages as Read in Messages App for iOS

The next time you have a bunch of messages – iMessages or text messages – you want to mark as read in iOS, just do the following:

  1. Open the Messages app on the iPhone or iPad
  2. Tap the “Edit” button in the corner and then at the bottom of the Messages app tap on “Read All”

Read All Messages in iOS immediately

Simple, quick, and effective.

Marking All Messages as Read in iOS as demonstrated with iphone

This will remove all indicators of new messages, marking them as read; the blue icon that is alongside an unread thread, the number that is at the top of the Messages app screen, and the new/unread red badge icon with the number on it on the Messages app icon, at least until you get more messages that haven’t been read.

You can always opt to turn the red badges off entirely from any given app, Messages included, but that’s generally not recommended unless you’re really fed up with them, since without them you won’t have any obvious indicator there are new messages waiting to be read.

This is particularly helpful if you use an iPhone or iPad synced with another Mac or iOS device, where messages appear across the board on all devices, since often they don’t seem to register that a message has been read on one device. It’s also a great solution to when you pull an iOS device out of Do Not Disturb mode to find an onslaught of new message notifications that ultimately aren’t that important.

Similar tricks are available to mark all email as read on the iPhone and iPad, and do the same with Voice Mail on the iPhone too.

Source : osxdaily[dot]com
post from sitemap

Thứ Sáu, 20 tháng 3, 2015

Developing iBeacons Apps with Swift

0 Flares 0 Flares ×

Since the introduction of iBeacons with iOS 7 by Apple, a lot of things have been said and written about. iBeacon technology consist of a revolutionary way to keep track of the position of a device indoors and use location services, similarly to the GPS outdoors, and it’s based on the signal transmitted through Bluetooth (Bluetooth Low Energy specifically, or BLE) by beacon devices. iOS devices can do that also, as long as they run a proper application.

However, the most important thing is that iOS SDK allows to develop applications capable of monitoring for iBeacons, and then perform various actions, depending always on specific requirements. The use of iBeacons can be applied in a wide range of cases, especially for marketing purposes. For example, using iBeacons in retail stores targeted advertisements can be displayed on the customers’ devices once the device enters a beacon’s region, or keep track of the traffic in such stores. Actually, the example that I just described is already being used, and it can be evolved even further.

ibeacons-featured-photo

From the developer’s point of view, an iBeacon area can be monitored and handled almost like a location, therefore the meaning of regions exist in this case too. The only difference is that such a region is actually called beacon region. If you’ve ever worked in the past with location services, then you already know that the Core Location framework provides API to work with regions. With this, an app can be aware of whether and when a device enters or leaves a beacon region, how to identify and manage any found beacons and a lot more. Additionally, it’s possible for an app to track changes in the bluetooth state, so it can automatically stop monitoring for beacons and save resources when the bluetooth for some reason doesn’t operate.

Every iBeacon has an identity which is parted by three values:

  • ProximityUUID: This is a 128-bit value, known as Universally Unique Identifier or UUID (for simplicity in this text I’ll stick to the UUID term). We’ll discuss some details about this later, among them how a UUID is created. For now, it’s necessary just to say that this value is the one that distinguishes an iBeacon from another.
  • Major: Each iBeacon has two values used to distinguish it from others having the same UUID. The first one of them, also known as the most significant value, is this one, and almost always it specifies a sub-region inside a region of beacons that have the same UUID. For example, think of the scenario where somebody would like to use iBeacons in his house and have one in the living room, one in the kitchen, and one in the bedroom. In that case, all iBeacons should have the same UUID so they belong to the same region (let’s say house region), and different major values so each sub-region of the house to be properly represented by each iBeacon. In rare cases and under certain, app-specific conditions only, the major value could mean something other than a sub-region.
  • Minor: This is the second value I mentioned above, and it’s also called least significant value. It’s used to divide a sub-region specified by the major value even further, and always in accordance to the requirements of the app that gets developed. In the hypothetical scenario I presented right before, the minor value can specify the sub-area of a room, for example a region next to a window or to the closet.

Besides the above, an iBeacon, or more accurately a beacon object (described by the CLBeacon class), has also the properties presented right next. Those are really handy when it’s necessary to deal with the distance of a found beacon from the device:

  • Proximity: This property describes the distance between the device and a found iBeacon. Actually, it’s a structure (struct), and it uses the far, near, and immediate values to describe the distance.
  • Accuracy: When two or more beacons exist in the same distance from the device, or in other words they have the same proximity value, then the accuracy will determine the closest one. Its value represents the distance in meters.
  • RSSI (or Received Signal Strength): As its name suggests, it is the strength of the bluetooth signal. It’s measured in decibels, and this is a read-write property. However, setting the rssi value is not as simple as assigning a new value to it. You’ll see later how this is achieved. For example, the rssi can be used to increase the signal strength of a beacon and reduce the strength of another one, in case extra calibration is needed or specific beacons should be easier to be found than others.

From the last three properties we’ll use just the proximity in this tutorial. However, it’s not hard to use the other two as well.

As a last word, all the information I just gave you consist of a standard knowledge that you should possess before you proceed in the next parts of the tutorial. If you feel so, please go ahead and search for more info in the Apple’s official documentation.

With all the above have been told, let’s “enter to the beacons’ regions” straight away. There are really interesting things awaiting for us!

An Overview of the Demo Applications

Let me start by saying that the title of this part has not a typographic error, and you are reading it correctly. In this tutorial we are not going to implement just one application, but two! Yes, two. As you will discover by the end of this tutorial, even though they’ll not be complicated enough, they are going to be just as good as needed so you get the grasp and learn how to work with iBeacons.

For both applications I provide you a starter project, which you can download here. In those projects a minimum implementation has already been done. Both the apps are universal, so you can run them in any device you have or desire (iPhone or iPad). Obviously, you need to download and open them in Xcode if you’re about to follow step by step.

Let me go now to some details regarding each app. The first one is named BeaconPop, and is going to be acting as an iBeacon; it will broadcast a signal using bluetooth so it is detectable and discoverable by other devices. Right next you can see a how the BeaconPop app looks like:

ibeacons-pop2

As you witness, besides the various informative labels being here and there, there are three important subviews: Two textfields for setting the major and minor values of the devices, and a button that will be used to start and stop the beacon advertisement functionality. The UUID value will be set in code, as it’s a value that is not supposed to be changed once it has been set.

Besides those three subviews, there’s one interesting label shown in the above image, the one at the bottom of the screen. In it, the bluetooth state is going to be displayed as long as the app runs. As you’ll see in more details later on, knowing the state of the bluetooth at any time is crucial for the behavior of the app. Not only new actions should be taken when the bluetooth state changes, but also valuable resources can be wasted if the bluetooth is, for example, off and the device keeps broadcasting. Anyway, we’ll see that in just a while.

There are two things that you should note regarding this app (they are irrelevant to each other): First, don’t expect the app to be working when being in the background. An iOS device can act as an iBeacon only when it runs in the foreground. Don’t forget about this fact. Second, you can dismiss the keyboard that’s being displayed when editing the textfields simply by swiping towards bottom. This behavior is already implemented in the starter project.

Now, let me say a few words about the second app. This is called BeaconSpot and it will do the exact opposite thing than the first one: It will monitor for beacons. Here’s a screenshot of it:

ibeacons-pop

This app actually will do nothing more than simply providing us with the details (major, minor, distance) of an iBeacon that has been discovered, once it has entered in such a region. As you can see in the image, there’s one button only and it will be used to start and stop the monitoring process.

Now, let me give you a couple of facts regarding both apps:

  • During the implementation process we are going to use the Core Location framework. In the BeaconPop app this usage will be limited, but in the BeaconSpot clearly is going to be more extended.
  • Both applications are going to use the same UUID value.
  • Make sure to turn the bluetooth on in all devices that you’re going to run the apps. For the broadcasting app, feel free to “play” around with the bluetooth, so you can see how it reacts in the bluetooth state changes.
  • Upon the first run of each app, you’ll be asked for permissions by both apps. Apparently, you should allow them to use location services. Remember that you can change these kind of settings at any time in the Settings app.

Finally, as I mentioned earlier about the BeaconPop app, the BeaconSpot must be running too in the foreground to operate. As I always say, just before we begin make sure to go through both the starter projects, and view the existing code and the storyboard in the Interface Builder. It’s important you feel familiar with both projects during implementation.

Generating a UUID String

So, let’s dive right in the work we have to do today, but before we write any code at all, it’s necessary to perform a prerequisite step. That is to create a UUID string that we’ll use later on in both of our projects. The UUID word is an abbreviation of the Universally Unique Identifiers term, and you can find more about it here. In short, a UUID is a 128-bit value that is used to uniquely identify an item, and it and looks like this:

AD5C5B73-5D1B-4458-AAA7-E31BE2077007

Regarding iOS, Apple provides the NSUUID class for handling UUID values. It’s a really simple class, and you can see its details here. We’re going to create instances of this class in both of our projects, but we won’t do anything special with them. We’ll just use where they’re needed during implementation.

Having done this small intro about the UUID values, let’s move forward to create one, and for this purpose we’ll use the Terminal Mac app. So, either open the Launchpad > Other > Terminal, or simply type “Terminal” in the Spotlight, so the terminal window appears. Once you have it right in front of you, type only the following command and hit Return:

uuidgen

Instantly, a new UUID value will be created and displayed in the Terminal window, right as shown below:

t31_3_new_uuid

If you don’t want to create your own UUID value right now, you can just use the one I generated in the previous image. Here it is as text, so you can copy-paste it later:

F34A1A1F-500F-48FB-AFAA-9584D641D7B1

If you create your own UUID value, then for the time being don’t close the Terminal app. You’ll need to copy the UUID in the next part. In any case however, you can generate a new one whenever you need it.

Broadcasting with BeaconPop

Now that we’ve generated the UUID value, we can proceed to the implementation of the two apps. We’re going to start by the broadcasting application for two reasons: First, it’s easier to be implemented. Second, it is more reasonable to build it first, as it would be really nice to have it already working as an iBeacon we’ll finish with the implementation of the second application.

So, we’ll make our hands dirty starting by the BeaconPop app. If you haven’t still downloaded the starter project, now it’s the best time to do it so you can come along. Before we write the first line of code, it’s necessary to explain a few things about how an iOS device works as a beacon. Among the data that a beacon transmits is the UUID, the major and minor values, and the RSSI value that expresses the strength of the signal. In order for a receiver application to “read” these values and then perform any needed actions based on them, it must be possible to acknowledge that there is actually an iBeacon somewhere around. And this can be done only by the broadcasting app, as it is its job to make known to other application that works as an iBeacon. So, the question that arises now, is how is this achieved?

Well, that’s easy indeed, as all it has to do the broadcasting application is to initialize and advertise a special Core Location region, named Beacon Region. Programmatically, such a region is represented by the CLBeaconRegion class, and an instance of it is created using the detailed values (UUID, major and minor values, etc) that the iBeacon must promote. As you we will seen pretty soon, creating a beacon region in code is amazingly easy, and if you have ever worked with Core Location services and classes, this one will seem much simpler.

What I just said is the first fact that you should be aware of before we do some coding. The other thing that you should also know, is that we have to check and react to any Bluetooth state changes. As you already know, in order for a device to work as a beacon (iOS device, or a real beacon device), it must transmit data using bluetooth signal. In iOS, there’s not guarantee that the BT will be always working, as the user can disable it at any given time. Besides that, BT might not be supported to all devices, or more generally, the BT might enter to a state other than the expected one (powered on state) without the user being aware of that. Of course, the broadcasting app’s behavior should be changed in accordance to the bluetooth state, and it’s our duty to do that. So, as you understand, further than creating a beacon region and broadcasting data, we also have to keep track of such BT state changes, and of course, perform the appropriate actions.

Having said all the above, it’s time to pass from theory into action. To keep things simple, we’ll see all the aforementioned stuff in separate steps.

Enabling and Disabling Broadcasting

First of all, make sure that you open the BeaconPop application in Xcode. For starters, open the ViewController.swift file and declare the following variables at the top of the class, right under the IBOutlet properties:

1
2
3
4
5
6
7
8
9
let uuid = NSUUID (UUIDString : "F34A1A1F-500F-48FB-AFAA-9584D641D7B1" )

var beaconRegion : CLBeaconRegion !

var bluetoothPeripheralManager : CBPeripheralManager !

var isBroadcasting = false

var dataDictionary = NSDictionary ( )

The uuid constant is an object of the NSUUID class. I talked about it in the last part. As you see, we initialize it at the same time we declare it. The generated UUID value is passed as an argument to the init method, and by writing that line only, we’re finished with it.

Next, we declare a CLBeaconRegion property. This property is the beacon region I said about earlier, and as you understand, it’s really important to this project.

Equally important is the next property named bluetoothPeripheralManager, which is an object of the CBPeripheralManager class. Through this object, we’ll be able later to monitor the bluetooth state changes and act appropriately. I provide no more details right now, as we’ll see how it’s used in just a while.

The last two variables are going to play a purely assistive role. As you assume, the isBroadcasting flag will indicate whether the device is broadcasting or not, and as initially this is not happening, its value is set to false. The dataDictionary is a NSDictionary object that we will need when the broadcasting will be starting.

At this point, let me underline two facts: First of all, it’s important for you to notice that the following two frameworks have been imported to the beginning of the file:

1
2
import CoreLocation
import CoreBluetooth

Without them, it won’t be possible for the device to operate as an iBeacon. The CoreLocation framework is needed to define the beacon region and work with it, while the CoreBluetooth framework is necessary for accessing the bluetooth component of the device.

The second thing that I want to highlight, is that for the time being we won’t initialize the bluetoothPeripheralManager object, but we’ll use it in our code normally, as if it were initialized. We’ll focus on that property in the next part of this section.

Our next step is to enable broadcasting. We want this to happen when the Start button is tapped on the app’s interface, therefore we are going to work in the switchBroadcastingState(_:) IBAction method. We’ll enable broadcasting under two certain conditions: The isBroadcasting flag must be false, meaning that currently no broadcasting is taking place, and of course, we must make sure that the bluetooth is powered on (enabled). Here’s what I just said translated into code:

1
2
3
4
5
6
7
@IBAction func switchBroadcastingState (sender : AnyObject ) {
    if !isBroadcasting {
        if bluetoothPeripheralManager.state == CBPeripheralManagerState.PoweredOn {

        }
    }
}

Now, if both of the above conditions are true, we have to do the following:

  1. To initialize the beacon region.
  2. To start advertising the region.
  3. To update the interface as necessary, by changing the button’s title, by indicating that the device is broadcasting, and by disabling both the textfields, so the user is unable to change the major and minor values during broadcasting.
  4. To indicate in code that the device is broadcasting.

Let’s see the first step in code:

1
2
3
4
5
6
7
8
9
@IBAction func switchBroadcastingState (sender : AnyObject ) {
    if !isBroadcasting {
        if bluetoothPeripheralManager.state == CBPeripheralManagerState.PoweredOn {
            let major : CLBeaconMajorValue = UInt16 (txtMajor.text.toInt ( ) ! )
            let minor : CLBeaconMinorValue = UInt16 (txtMinor.text.toInt ( ) ! )
            beaconRegion = CLBeaconRegion (proximityUUID : uuid, major : major, minor : minor, identifier : "com.appcoda.beacondemo" )
        }
    }
}

At first, we convert the major and minor values that have been already set in the textfields to numbers. The CLBeaconMajorValue and CLBeaconMinorValue types are nothing else than UInt16 numbers (16-bit unsigned int), and you can find this out from the conversion that takes place in the first two lines. Once we acquire them, we proceed to the initialization of the beacon region. If you start typing the above initializer, you’ll see that the class provides more than one initializers, however the above is the proper one that must be used. As you witness, actually four values must be provided as arguments:

  1. The UUID value we generated in the previous part. Here’s where it’s needed in this app.
  2. The major value.
  3. The minor value.
  4. A unique string identifier that is set for the specific beacon region. The same value we’re about to use in the receiver app too.

Next, we must advertise the above region, so when a receiver app is nearby to be able to identify the beacon. This is achieved with the next two lines:

1
2
3
4
5
6
7
8
9
10
@IBAction func switchBroadcastingState (sender : AnyObject ) {
    if !isBroadcasting {
        if bluetoothPeripheralManager.state == CBPeripheralManagerState.PoweredOn {
            ...

            dataDictionary = beaconRegion.peripheralDataWithMeasuredPower ( nil )
            bluetoothPeripheralManager.startAdvertising (dataDictionary )
        }
    }
}

Some explanation now. When using a device as an iBeacon, it’s possible to transmit some extra data besides the values we specified in the beacon region initializer, and this is achieved by using a dictionary object. In this example we don’t do something like that, but no matter what, this dictionary must be initialized using the RSSI value of the device (the signal strength). This value can be set using the peripheralDataWithMeasuredPower(:) method, and you can either set a specific value as an argument (remember that value represents the decibels), or leave it nil so the app uses the default RSSI value of the device. Regarding the advertising now, it is initiated by using the startAdvertising(:) method of the bluetoothPeripheralManager object, and it takes just one argument: The dictionary with the data to transmit. That’s the reason we first create the data dictionary, and then we start advertising.

Now, let’s update our interface as needed:

1
2
3
4
5
6
7
8
9
10
11
12
13
@IBAction func switchBroadcastingState (sender : AnyObject ) {
    if !isBroadcasting {
        if bluetoothPeripheralManager.state == CBPeripheralManagerState.PoweredOn {
            ...

            btnAction.setTitle ( "Stop", forState : UIControlState.Normal )
            lblStatus.text = "Broadcasting..."

            txtMajor.enabled = false
            txtMinor.enabled = false
        }
    }
}

Lastly, let’s indicate that the device is broadcasting:

1
2
3
4
5
6
7
8
9
@IBAction func switchBroadcastingState (sender : AnyObject ) {
    if !isBroadcasting {
        if bluetoothPeripheralManager.state == CBPeripheralManagerState.PoweredOn {
            ...

            isBroadcasting = true
        }
    }
}

That’s it. Now, when tapping on the Start button the app is capable to be working as an iBeacon. However, we’re not over yet, as we must take the exact opposite path and stop the broadcasting by tapping once again in the button, this time titled “Stop”. In the first ifstatement above we will add an else case, and in there we will perform the next tasks:

  1. We’ll stop the beacon advertising.
  2. We’ll update the interface.
  3. We’ll indicate that the device is no longer broadcasting.

Here are all the above in one snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@IBAction func switchBroadcastingState (sender : AnyObject ) {
    if !isBroadcasting {

    }
    else {
        bluetoothPeripheralManager.stopAdvertising ( )

        btnAction.setTitle ( "Start", forState : UIControlState.Normal )
        lblStatus.text = "Stopped"

        txtMajor.enabled = true
        txtMinor.enabled = true

        isBroadcasting = false
    }
}

The first part in creating the broadcasting app is now ready, so let’s go to the next one.

Tracking Bluetooth State Changes

In the above IBAction method we used the bluetoothPeripheralManager property to get the state of the bluetooth, but if you remember up to that point we hadn’t initialize it. We said that this will take place at a later time, and this time is right now. Begin by going to the viewDidLoad method. There you’ll find some code already existing, but regardless that, all you have to do is to add the next line:

1
2
3
4
5
override func viewDidLoad ( ) {
    ...

    bluetoothPeripheralManager = CBPeripheralManager (delegate : self, queue : nil, options : nil )
}

The important in the above initialization is to set our class as the delegate of the bluetoothPeripheralManager object. But, as you understand that by doing that, it’s necessary to adopt the CBPeripheralManagerDelegate protocol:

1
class ViewController : UIViewController, CBPeripheralManagerDelegate

Okay, now there is one delegate method that we have to implement. This method provides us with all the possible BT states, and it’s our work to handle each one separately. Obviously, the reaction of the app upon a BT state change is not common for all applications; everything depends on the app nature, requirements, and so on.

Let me become now more specific and say that among all the states that we are about to see, we are actually interested in just two of them in this sample application: The powered on and off states of the BT. We already used the first case in the previous implementation, where we allowed the app to broadcast if only the BT is powered on. If at some point the state goes to off, we must make sure that the app won’t keep trying to broadcast, so we must disable that functionality once the state gets changed. For the rest BT states you’ll see next, we are not going to do anything particular; instead, we’ll just prepare a custom message describing each state, and then we’ll display it in the lblBTStatus label.

So, with all the above said, here’s the second important part of our application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
func peripheralManagerDidUpdateState (peripheral : CBPeripheralManager ! ) {
    var statusMessage = ""

    switch peripheral.state {
    case CBPeripheralManagerState.PoweredOn :
        statusMessage = "Bluetooth Status: Turned On"

    case CBPeripheralManagerState.PoweredOff :
        if isBroadcasting {
            switchBroadcastingState (self )
        }
        statusMessage = "Bluetooth Status: Turned Off"

    case CBPeripheralManagerState.Resetting :
        statusMessage = "Bluetooth Status: Resetting"

    case CBPeripheralManagerState.Unauthorized :
        statusMessage = "Bluetooth Status: Not Authorized"

    case CBPeripheralManagerState.Unsupported :
        statusMessage = "Bluetooth Status: Not Supported"

    default :
        statusMessage = "Bluetooth Status: Unknown"
    }

    lblBTStatus.text = statusMessage
}

Notice that in case the BT is turned off, we check if the device is currently broadcasting or not. If it is, then we call the IBAction method so all the proper tasks to be performed and the broadcasting to be stopped. Once again, depending on the requirements of the app you’re developing, you might need to handle each state in a different manner; now you’ve been shown the way, so it’s up to you to apply any missing logic.

Final Touches

So, our broadcasting app is now almost ready, and it works, but it’s not perfect. There are some final touches missing yet, which if attached to it, they’ll make it even better, and even though it’s a demo app, I consider the extra behavior that we’ll add here quite important.

If you recall, during the beacon region initialization, we used the textfields’ values as the major and minor values for the beacon. Now, what is it going to happen if any of these two values is missing? And how should the app act in such a case? Well, there are various possible solutions to that, and the proper one definitely depends on the nature of the app. Here we can easily workaround this problem if we simply do not allow the app to start broadcasting if any of those two values is missing. Maybe we could even display a message to the user saying that both values are required (but we won’t do it).

In addition to the above, it would be a nice idea to prevent the broadcasting when the keyboard is visible, and the user is still editing either the major or the minor value.

So, with the those two thoughts in mind, you’re given once again the IBAction method containing the new additions at the beginning of it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@IBAction func switchBroadcastingState (sender : AnyObject ) {
    if txtMajor.text == "" || txtMinor.text == "" {
        return
    }

    if txtMajor.isFirstResponder ( ) || txtMinor.isFirstResponder ( ) {
        return
    }

    if !isBroadcasting {
        if bluetoothPeripheralManager.state == CBPeripheralManagerState.PoweredOn {
            let major : CLBeaconMajorValue = UInt16 (txtMajor.text.toInt ( ) ! )
            let minor : CLBeaconMinorValue = UInt16 (txtMinor.text.toInt ( ) ! )
            beaconRegion = CLBeaconRegion (proximityUUID : uuid, major : major, minor : minor, identifier : "com.appcoda.beacondemo" )

            dataDictionary = beaconRegion.peripheralDataWithMeasuredPower ( - 58 )

            bluetoothPeripheralManager.startAdvertising (dataDictionary )

            btnAction.setTitle ( "Stop", forState : UIControlState.Normal )
            lblStatus.text = "Broadcasting..."

            txtMajor.enabled = false
            txtMinor.enabled = false

            isBroadcasting = true
        }
    }
    else {
        bluetoothPeripheralManager.stopAdvertising ( )

        btnAction.setTitle ( "Start", forState : UIControlState.Normal )
        lblStatus.text = "Stopped"

        txtMajor.enabled = true
        txtMinor.enabled = true

        isBroadcasting = false
    }
}

At this point the BeaconPop app is ready, and fully functional. You can run it if you desire, but without its counterpart which is the next app, you won’t be able to see any results. So, take a breath here, and when you’re ready, let’s keep going!

Finding Beacons With BeaconSpot

In the second app that we have to implement in this tutorial, we’ll do the exact opposite thing than before; we will track all the nearby devices that advertise themselves as iBeacons. Now that we have finished working in the BeaconPop project feel free to close it, and then make sure to open the BeaconSpot starter project in Xcode. Our work here is quite specific. What we’ll do is to monitor for beacon regions using location services and the Core Location API, and once such a region is found, we’ll range all beacons in it. If there are more than one beacons in region, then we’ll fetch the closest one, and then we’ll display its details on the screen.

Likewise the previous app, we are going to use a button to start and stop the region monitoring, and eventually all the rest functionalities. Note however that this is not a rule, it’s just how I chose to develop this specific app. It’s quite possible that this approach won’t fit in your needs, and you might want to start monitoring for regions once the app gets launched. As I always love to say, I show you the way, but you’re the one that you’ll customize everything according to the requirements of your under development app. Contrary to the BeaconPop app, here we’ll work more with the CoreLocation framework. Specifically, further than using a beacon region object, we’ll also use a location manager, and several delegate methods that are provided by the CLLocationManagerDelegate protocol. There’s no need to go into more details now, as everything will become clear as we move along.

Before we start coding, let me explain shortly the “plan” that we’re going to follow. As I already mentioned, we are going to use the button to start monitoring for beacon regions. Once the app detects such a region, and when it actually detects that is inside such a region, it will start ranging the nearby beacons. All the found beacons within range are provided to us in an array through a really useful delegate method. In that array, the closest beacon is positioned in the first index, while the farthest one to the last one. Practically, that means that by simply “extracting” the first beacon from the array, we have in our hands the closest beacon. How are we going to use it? Well, I leave this for later. We’ll discuss about it when we’ll get there. Lastly, when the app exits from a beacon region, it will stop the ranging process (it will start again when it enters a region). It would be a total waste of resources to keep ranging while the device isn’t inside the range of a beacon. By tapping once again the button, the app will instantly stop monitoring and ranging, no matter whether is inside a beacon region or not.

That’s all you need know before we start programming. Let me note that in this app I’m not going to bother about the bluetooth state of the device, whether it’s working or not, or generally to track its state changes. I intentionally skipped it, as this demo application should end at some point. Additionally, you’ve already been given with the necessary code on how to do so, therefore you know how to be programmatically informed about bluetooth state changes if you need to.

Let’s get started. As we did in the previous app, we’ll begin here too by declaring all the variables that we’ll need throughout the implementation. Make sure that you’ve opened the ViewController.swift file, and you’re in the beginning of the class. Here they are:

1
2
3
4
5
6
7
8
9
var beaconRegion : CLBeaconRegion !

var locationManager : CLLocationManager !

var isSearchingForBeacons = false

var lastFoundBeacon : CLBeacon ! = CLBeacon ( )

var lastProximity : CLProximity ! = CLProximity.Unknown

The beaconRegion property will be used to specify the kind of region that the app should monitor for, and as you’ll see next, we’ll provide it with the UUID value we generated earlier. This object will be used later in conjunction with the locationManager object, right when the app should start monitoring for regions. The isSearchingForBeacons flag will let us know whether the app is searching or not (monitoring or not) for beacons, and depending on its value we’ll perform the proper actions. Finally, in the lastFoundBeacon and lastProximity properties we’ll store (as their names suggest) the closest beacon that was last found, and its most recent proximity value respectively. Both of these properties will assist us to avoid unnecessary UI updates when the beacon or its proximity haven’t changed since the last ranging.

Now, it’s time to do some initialization, so go to the viewDidLoad method and add the following content:

1
2
3
4
5
6
7
8
9
10
11
12
override func viewDidLoad ( ) {
    ...

    locationManager = CLLocationManager ( )
    locationManager.delegate = self

    let uuid = NSUUID (UUIDString : "F34A1A1F-500F-48FB-AFAA-9584D641D7B1" )
    beaconRegion = CLBeaconRegion (proximityUUID : uuid, identifier : "com.appcoda.beacondemo" )

    beaconRegion.notifyOnEntry = true
    beaconRegion.notifyOnExit = true
}

At first, we initialize the location manager property, and we set our class as its delegate. That’s necessary, as we’re going to use several of the delegate methods it provides.

Then, we initialize the beacon region using the UUID and the identifier values only. Note that this is a different initializer than the one we used in the broadcasting app. There, we had to provide it with the major and minor values as well. Here, this is not needed. Also, keep in mind that both the broadcasting app and this one should use the same UUID value. If you change it to any of the apps, then there’s no case the iBeacon to be spotted by this app, even if the devices are “sitting” next to each other.

Lastly, by using the notifyOnEntry and notifyOnExit properties of the beacon region object, we make sure that the app will become aware when it enters or leaves a beacon region area. This is useful, as it will determine whether the beacon ranging should be started or should be stopped.

At this point, Xcode is displaying an error. That’s because the CLLocationManagerDelegate protocol is not adopted yet by our class, so let’s fix it:

1
class ViewController : UIViewController, CLLocationManagerDelegate

Now, let’s handle the case where the user taps on the “Start Spotting” button, and the region monitoring should begin. As you may already now, when using Core Location services it’s necessary to request for users’ permission for monitoring for region changes and getting location updates, and that’s something that we are about to do here too. In iOS 8, a new, important step was added to that step, which if omitted the app is not going to work. That is to include a new item in the .plist file regarding the description that will be displayed to the user regarding the permissions to track location changes. More specifically, in the .plist file of the app create a new item with the following key:

NSLocationAlwaysUsageDescription

The value matching to that key is a string, and it’s a complementary description to the default one that the system will display to the user. In that case, just any description you want, or use this: “Need permission to spot iBeacons.”

Generally speaking now, the above key is used in cases where the app needs to use location services all the time, even when it runs on the background. In case you want your app to use location services only when it’s in the foreground, then use the NSLocationWhenInUseUsageDescription key instead. However, it’s not just those two keys in the .plist file that define the location services usage type. It’s also important to specify that in code, exactly as we’ll do right next.

t31_4_plist_usage

Back in the switchSpotting(_:) IBAction method now, here’s what we’re going to perform so the app starts to monitor for beacons:

  1. Request for authorization, as described above.
  2. Start monitoring for beacon regions.
  3. Start updating the location of the device.
  4. Update the interface.

In code:

1
2
3
4
5
6
7
8
9
10
11
12
@IBAction func switchSpotting (sender : AnyObject ) {
    if !isSearchingForBeacons {
        locationManager.requestAlwaysAuthorization ( )
        locationManager.startMonitoringForRegion (beaconRegion )
        locationManager.startUpdatingLocation ( )

        btnSwitchSpotting.setTitle ( "Stop Spotting", forState : UIControlState.Normal )
        lblBeaconReport.text = "Spotting beacons..."
    }

    isSearchingForBeacons = !isSearchingForBeacons
}

Note that initially we check if the device is searching for beacons or not. Also, don’t overlook the last line in the above method. With it, we change the flag’s value, so the next time that the user will tap on the button the monitoring will stop (we’ll do that later).

The requestAlwaysAuthorization() method of the location manager in combination with the key we added in the .plist file, is going to make sure that the user will be asked for the proper permissions before the app starts using any location services. If either this command or the .plist entry is missing, the app won’t work.

Once we make the app start monitoring for beacon regions (regions that we specified in the initialization of the beaconRegion object) it’s necessary right next to use a couple of delegate methods and ask the system to check if the device is already in a region of interest or not. Note that if we don’t perform the following tasks, the app won’t really know if the device is inside a beacon region or not when it starts running, even if it really is. Even more, it won’t be aware of that until it exits the region and re-enters again.

So, at first we need to request the state of the region as shown next:

1
2
3
func locationManager (manager : CLLocationManager !, didStartMonitoringForRegion region : CLRegion ! ) {
    locationManager.requestStateForRegion (region )
}

This delegate method is called immediately right after the device has started monitoring for regions. The answer to the above request is given to the delegate method that is shown below:

1
2
3
4
5
6
7
8
func locationManager (manager : CLLocationManager !, didDetermineState state : CLRegionState, forRegion region : CLRegion ! ) {
    if state == CLRegionState.Inside {
        locationManager.startRangingBeaconsInRegion (beaconRegion )
    }
    else {
        locationManager.stopRangingBeaconsInRegion (beaconRegion )
    }
}

The above delegate method contains the state parameter, which is actually a CLRegionState struct and it “tells” us whether the device is inside the desired region or not. In our case, if it is then we must start ranging the nearby beacons, and that’s what exactly we do. Note that the above method doesn’t get called only when we request for the region state; it’s called every time the device enters or leaves a region, therefore is necessary to have an else case. In it, we only have to stop ranging beacons.

For your information, here’s the declaration of the CLRegionState struct:

1
2
3
4
5
enum CLRegionState : Int {
    case Unknown
    case Inside
    case Outside
}

As I said right before, the last delegate method is also called when the device crosses the boundary of a region, either it enters on it or exits. In any of those cases, what we only have to do is to update our interface, as the beacon ranging has already been handled. Here are the two respective delegate methods that are used to do that exactly:

1
2
3
4
5
6
7
8
9
10
func locationManager (manager : CLLocationManager !, didEnterRegion region : CLRegion ! ) {
    lblBeaconReport.text = "Beacon in range"
    lblBeaconDetails.hidden = false
}


func locationManager (manager : CLLocationManager !, didExitRegion region : CLRegion ! ) {
    lblBeaconReport.text = "No beacons in range"
    lblBeaconDetails.hidden = true
}

Now, let’s focus on the beacon ranging. When this process is taking place the following delegate method is being called:

1
func locationManager (manager : CLLocationManager !, didRangeBeacons beacons : [AnyObject ] !, inRegion region : CLBeaconRegion ! ) { }

The beacons array contains the all the beacons found, and as I said to the beginning of this part, the object in the first position of the array represents the closest beacon. Our goal here is to get the details of it (major and minor values, distance), and display them to the user. But, as this method is called almost every second, it’s totally unnecessary to keep updating the interface while the closest beacon remains the same. So, what we’ll do to avoid this is simple: We’ll store the closest beacon to the lastFoundBeacon property, and its distance from the device (or in other words the proximity) to the lastProximity property. Then, we’ll compare both the last found beacon and the proximity to the new ones, and if any of them has changed we’ll update the interface. Otherwise, we won’t.

As you’ll see in the next code snippet, the details of the found beacon are presented as a formatted string to the lblBeaconDetails label. By default, this label is hidden and becomes visible only when there’s actual beacon data to display. However, if no beacons are found or any other problems exists (for example, a nil value), the label becomes hidden again. In the code that follows, notice all the checks that take place until we actually display the beacon data to the user:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
func locationManager (manager : CLLocationManager !, didRangeBeacons beacons : [AnyObject ] !, inRegion region : CLBeaconRegion ! ) {
    var shouldHideBeaconDetails = true

    if let foundBeacons = beacons {
        if foundBeacons.count > 0 {
            if let closestBeacon = foundBeacons [ 0 ] as? CLBeacon {
                if closestBeacon != lastFoundBeacon || lastProximity != closestBeacon.proximity   {
                    lastFoundBeacon = closestBeacon
                    lastProximity = closestBeacon.proximity

                    var proximityMessage : String !
                    switch lastFoundBeacon.proximity {
                    case CLProximity.Immediate :
                        proximityMessage = "Very close"

                    case CLProximity.Near :
                        proximityMessage = "Near"

                    case CLProximity.Far :
                        proximityMessage = "Far"

                    default :
                        proximityMessage = "Where's the beacon?"
                    }

                    shouldHideBeaconDetails = false

                    lblBeaconDetails.text = "Beacon Details:\nMajor = " + String (closestBeacon.major.intValue ) + "\nMinor = " + String (closestBeacon.minor.intValue ) + "\nDistance: " + proximityMessage
                }
            }
        }
    }

    lblBeaconDetails.hidden = shouldHideBeaconDetails
}

Besides all those I mentioned before, also note how the proximity of the beacon is handled. In the above implementation you can see all the possible values of the CLProximity struct. Depending on the proximity value, we specify the message that will be displayed. Of course, the above approach is just for demo reasons, and in a real app you should probably take some actions based on each proximity value.

The above method is the last important thing regarding the beacon monitoring we have to do in this application. Additionally, we should never forget that is possible errors to occur, so let’s implement a few delegate methods where we’ll just output the error message. You’ll understand what each method is for by its name:

1
2
3
4
5
6
7
8
9
10
11
12
13
func locationManager (manager : CLLocationManager !, didFailWithError error : NSError ! ) {
    println (error )
}


func locationManager (manager : CLLocationManager !, monitoringDidFailForRegion region : CLRegion !, withError error : NSError ! ) {
    println (error )
}


func locationManager (manager : CLLocationManager !, rangingBeaconsDidFailForRegion region : CLBeaconRegion !, withError error : NSError ! ) {
    println (error )
}

Now, let’s make the app capable of stopping spotting beacons when the button gets tapped once again. Back in the one and only IBAction method, we’ll add an else case as shown next:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@IBAction func switchSpotting (sender : AnyObject ) {
    if !isSearchingForBeacons {
        ...
    }
    else {
        locationManager.stopMonitoringForRegion (beaconRegion )
        locationManager.stopRangingBeaconsInRegion (beaconRegion )
        locationManager.stopUpdatingLocation ( )

        btnSwitchSpotting.setTitle ( "Start Spotting", forState : UIControlState.Normal )
        lblBeaconReport.text = "Not running"
        lblBeaconDetails.hidden = true
    }

    isSearchingForBeacons = !isSearchingForBeacons
}

As you can see, we stop everything, even the beacon ranging in case is being performed. Also, we update the interface accordingly.

With the above addition, the BeaconSpot app is ready too!

Running the Apps

Now that both of the demo applications of the tutorial have been implemented, you can go ahead and test them. It’s important to keep in mind that you should run them in real devices, no matter if they’re iPhones or iPads. The ideal case for testing is to use at least three devices that run iOS 8 (8.1 or above specifically), where the two of them would act as iBeacons, and the third one would search for them. However, make sure that the broadcasting devices won’t have the same major and minor values, as it will be impossible for the BeaconSpot app to identify them as two different beacons.

If you don’t have three iOS devices, there are a couple of two other options you can use so you test the apps (or at least the BeaconSpot):

  1. Use real beacons. There are various companies out there making and selling beacon devices that use Bluetooth Low Energy technology (BLE), and if you’re interested in them in real, you should buy some. Maybe it isn’t worth doing so just for testing the demo app, but if you think that you could use them in the future too, then go ahead and grab some. Usually more than one beacons are sold together in a package. Before using a real beacon some extra work is required so you “program” them properly and assign the desired UUID, major, minor, etc, values, but the way you should do that totally depends on the manufacturer’s guides of the beacons you’ll get. As you guess, I’m not going to propose any manufacturer at all, there are a few out there, so the final decision it’s yours.
  2. Allow your Mac to act as a beacon device. To do that, two conditions must be met: First of all, you must make sure that your computer’s bluetooth is version 4.0, otherwise it’s not going to work. If you have an older version than that, you could optionally buy a proper bluetooth USB dongle (BLE 4.0) that’s really cheap, and upgrade that way the bluetooth of your Mac.The second condition is to find in the Internet (and probably in the GitHub) a Mac application that will let you specify all the broadcasting details and then transmit through the bluetooth. I don’t think that you’ll find any application to do that on the Mac App Store, so you might need to search a bit. Even though it is said that in Yosemite it’s not doable something like that, trust me, it is, as I’ve already tested it. Right next you can see a screenshot of such a Mac app running in my computer:
t31_5_beacon_mac_app

Anyway, I’m pretty sure that you’ll figure out a way to test the apps. To keep things interesting, make sure that the devices acting as beacons are in some distance, so you have the opportunity to enter and exit to their regions. During testing, note how the proximity gets changed as you move closer to or farther from a beacon.

Here is a screenshot demonstrating both the BeaconPop and BeaconSpot apps running:

ibeacons-demo

Summary

From my experience I would say that working with beacons in real application is a bit more complicated than what I’ve showed you here, because the code must be adapted and fit to the under-development application logic, but everything is manageable and according to what you’ve already learnt. Probably you will rarely or never need to build an iBeacon app, except for demonstrative or testing purposes, but it’s almost certain that you’ll have to create a beacon receiver at some point (if, of course, you’ll be dealing with beacons). What you’ve seen here can help you create the backbone of a beacon-related app; all you have to do next is to customize it by applying the required logic. Needless to say that you’ll have to dig up more on all the aspects talked about today if you’re going to work with beacons, but don’t worry; nothing is eventually so hard to do. In any case, I think that dealing with iBeacons is a really funny and interesting work, and definitely you will agree that beacons can unveil a whole new world of possibilities. With that, I leave you to keep experimenting and remember that now you’ve been shown the way, go ahead and develop some really interesting and useful iBeacon apps. There are hundreds of different kind of uses, so go and take advantage of them!

For your reference, you can download the complete project here.

Source : appcoda[dot]com
post from sitemap