Brian Coleman

  • Home
  • ABOUT
  • SERVICES
  • PORTFOLIO
  • BLOG
  • Contact

Ios 23

Classix for iPhone, iPad & Apple TV

When Apple announced tvOS in September 2015 I did everything I could to learn it fast, I had been waiting to make my own Apple TV apps for years. I’ve always wanted to build a video platform app just like Netflix. If you’ve followed my blog you may have read my tutorials tvOS Tutorial: Make a Video App in Swift and tvOS Tutorial: Top Shelf in Swift. Those two tutorials were a nice start but there was a lot more work needed to make a Netflix app.

Since I’m not a publisher I don’t have rights to any content so I needed to find some. There are a couple of apps on iOS that have a nice library of classic movies and tv shows that are in the public domain. Little did I know how many great movies and TV shows are in the public domain, movies like House on Haunted Hill, Night of the Living Dead and TV shows like Looney Tunes. I downloaded a couple of these apps and saw that it was nice that you could watch those movies but the apps didn’t offer many features, the key features missing being a Recommendation Engine, My List and Continue Watching.

After spending hours and hours entering a large sample set of movies and tv shows into my database I built out the backend APIs that were needed, such as listing movies by categories, recommended movies, trending movies and recently added. I haven’t done much web programming in a long time, but my past knowledge of Perl and MySQL were enough to get the job done.

Next was the UI, sure I could have come up with a simple user interface but what’s simpler than the existing Netflix interface. So that’s what I used for iPhone, iPad and Apple TV. Netflix has a ton of users and more than likely the users of my app have already used Netflix so using the same interface would be very familiar.

“Classix, the Netflix for Classic Movies & TV Shows”

Screen Shot 2016-05-24 at 8.34.00 AM

Watch Now on Your iPhone®, iPad® and Apple TV®

Watch classic TV shows and movies recommended just for you. Classix has something for everyone. There’s even cartoons and movies just for kids with family-friendly entertainment.

Sign up for Classix Premium and receive no commercials and access to premium content. No hidden fees. One time in-app purchase. No recurring subscription needed.

How does Classix work?

• Classix adds TV shows and movies all the time. Browse titles or search for your favorites.
• The more you watch, the better Classix gets at recommending TV shows and movies that you’ll love—just for you.
• Save your favorites to your list and continue watching where you left off.
• Instantly stream on all iOS devices.

Simulator Screen Shot May 20, 2016, 6.12.54 PM

2

3

Simulator Screen Shot May 20, 2016, 6.13.12 PM

Simulator Screen Shot May 20, 2016, 6.15.35 PM

Find out more at http://www.classixapp.com

Twitter: @classixapp

Instagram: @classixapp

Facebook: http://www.facebook.com/ClassixApp

May 20, 2016 About Me, My Apps, tvOSapps, ios, swift, tvos

Tutorial: Rate Me using UIAlertController in Swift

We all know that good reviews for our apps will influence new users to download the app. It doesn’t help that there is no standard way to ask users for a review. The only way to get your app reviewed is on your app page within the App Store. How many people after downloading your app will again go back to AppStore, search for your app, go to rate screen and give you a rating? Not many outside of your own family and friends!

If you prompt the customer at some point while the app is running you’re always going to disrupt their workflow to some degree. You can alleviate this by trying to pick a moment that’s the least disruptive. If possible choose a moment when something positive or rewarding has just happened.

Below is a tutorial to help you add a Rate Me alert view in Swift.

Setup Rate Me

The method below will control the logic of when the Rate Me alert view is displayed to the user. Enter in the minimum number of sessions the app should be opened before showing the request to rate the app the first time and how often it should try again if the user selects “Maybe Later”. The numLaunches and neverRate values are stored using NSUserDefaults.

var iMinSessions = 3
var iTryAgainSessions = 6

func rateMe() {
    var neverRate = NSUserDefaults.standardUserDefaults().boolForKey("neverRate")
    var numLaunches = NSUserDefaults.standardUserDefaults().integerForKey("numLaunches") + 1
    
    if (!neverRate && (numLaunches == iMinSessions || numLaunches >= (iMinSessions + iTryAgainSessions + 1)))
    {
        showRateMe()
        numLaunches = iMinSessions + 1
    }
    NSUserDefaults.standardUserDefaults().setInteger(numLaunches, forKey: "numLaunches")
}

Using UIAlertController in Swift

UIAlertView is deprecated. Use UIAlertController with a preferredStyle of UIAlertControllerStyleAlert instead. Now UIAlertController is a single class for creating and interacting with what we knew as UIAlertViews and UIActionSheets on iOS 8.

If you would like to use UIAlertView with multiple actions, the method below is the best way to handle each button tapped. The advantage of using completion handlers is you can easily handle multiple alert views within a single view controller.

func showRateMe() {
    var alert = UIAlertController(title: "Rate Us", message: "Thanks for using ", preferredStyle: UIAlertControllerStyle.Alert)
    alert.addAction(UIAlertAction(title: "Rate ", style: UIAlertActionStyle.Default, handler: { alertAction in
        UIApplication.sharedApplication().openURL(NSURL(string : "itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id="))
        alert.dismissViewControllerAnimated(true, completion: nil)
        }))
    alert.addAction(UIAlertAction(title: "No Thanks", style: UIAlertActionStyle.Default, handler: { alertAction in
        NSUserDefaults.standardUserDefaults().setBool(true, forKey: "neverRate")
        alert.dismissViewControllerAnimated(true, completion: nil)
        }))
    alert.addAction(UIAlertAction(title: "Maybe Later", style: UIAlertActionStyle.Default, handler: { alertAction in
        alert.dismissViewControllerAnimated(true, completion: nil)
        }))
    self.presentViewController(alert, animated: true, completion: nil)
}

If you just need an alert view with a single action “Ok”, the following code will do.

let alert = UIAlertView()
    alert.title = "Alert"
    alert.message = "Here's a message"
    alert.addButtonWithTitle("Understod")
    alert.show()
July 30, 2014 Swift, Tutorialsios, swift, tutorial

How to use Apple’s Identifier for Advertisers (IDFA)

On the first of May, 2013, Apple began rejecting any app or app update in the App Store if it accessed UDIDs, moving app developers towards its own preferred ad tracking option, the Identifier for Advertisers (IDFA). IDFA stands for “identifier for advertisers.” It’s a random, anonymous number that is assigned to a user and their device. It is temporary and can be blocked, like a cookie.

If you need to uniquely identify a user, read below on how you can access the IDFA.

Retrieve iPhone IDFA

You first have to check if user user has decided to opt out from ad tracking. Only if he allowed it you use the IDFA.

You can check it by calling isAdvertisingTrackingEnabled method of ASIdentifierManager.

isAdvertisingTrackingEnabled

Check the value of this property before performing any advertising tracking. If the value is NO, use the advertising identifier only for the following purposes: frequency capping, conversion events, estimating the number of unique users, security and fraud detection, and debugging.

ios7-privacy-advertising

The following code snippet shows how to obtain a string value of IDFA.

- (NSString *)identifierForAdvertising
{
   if([[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled])
   {
       NSUUID *IDFA = [[ASIdentifierManager sharedManager] advertisingIdentifier];

       return [IDFA UUIDString];
   }

    return nil;
} 

You’ll need to link with AdSupport framework. If you only target iOS 7 and above, you can add it using modules.

@import AdSupport;

How to Submit Your App When it Uses IDFA

Before you submit a new app or a new version of an existing app to Apple’s App Store, note that Apple has recently updated the IDFA settings so that you must agree to their revised terms of service by selecting a check box that indicates your compliance.

When you submit your apps with iTunes Connect, you’ll now be prompted with three checkboxes certifying your intentions to use IFA for:

  • Serve advertisements within the app.
  • Attribute this app installation to a previously served advertisement.
  • Attribute an action taken within this app to a previously served advertisement

To avoid app store rejections, ensure that you select the appropriate IDFA usage check-boxes for your app and honor Apple’s “Limit Ad Tracking” requirement.

IDFA_Page2-1

July 14, 2014 Tutorialsapple, ios, objective-c, tutorials

Framework: CoreBackground

Are you developing a new app for iOS7? If you are, you may want to consider using some of the new techniques that other apps are using to make it feel like a true iOS7 feeling app. If you’ve used the new Yahoo! Weather app you will have seen a nice blur light effect that they use as you scroll down the view. It’s a nice effect that makes the app look very polished.

CoreBackground is a set of Objective-C classes inspired by the iOS Yahoo Weather App. It provides iOS location-based Flickr backgrounds with Gaussian blur light effects for iPhone. As one scrolls over the foreground a Gaussian blur light effect is applied to the background. This provides for an engaging location-based UX while at the same time providing a canvas to apply readable content to the foreground. CoreBackground is a non-blocking “event-based” Objective-C block API and all rendering occurs in backing stores to preserve the main run loop. Make it be the foundation of your next iOS project today.

Setting up CoreBackground

Follow the steps below to get started:
1. Visit the GitHub page here:https://github.com/justinmfischer/core-background.
2. Pull or download the latest version of the source code.
3. Add the following required frameworks into your project:
– Accelerate.framework
– CoreLocation.framework
– CFNetwork.framework
– SystemConfiguration.framework
4. Start coding!

CoreBackground is comprised of 3 main Objective-C singleton managers all within the CBG header file (CBG.h).

  • CBGLocationManager : Provides cacheable location-based information.
  • CBGFlickrManager : Provides cacheable Flickr API content.
  • CBGStockPhotoManager : Provides local image content in case of reachability issues.

Prior to using CoreBackground a valid Flickr API key and shared secret is required. The sample project will successfully build (LLVM – Warning) without this information but will fall back to stock photos. The Flickr API key and shared secret can be obtained here. As of this writing Flickr restricts free (Non-Commercial) accounts to 3600 request per hour. Please make the following modifications below.

(CBGConstants.h)
//Flickr Auth
#define OBJECTIVE_FLICKR_API_KEY @"Ch@ngeMe"
#define OBJECTIVE_FLICKR_API_SHARED_SECRET @"Ch@ngeMe"

The constants file also contains a value to provide searchable Flickr photo tags. The sample project uses “bike” and will match any comma separated values. Example: “bike,ride,outdoor”

//Flickr Search
#define KFlickrSsearchTags @"bike"

Code: Sample Project

The CoreBackground sample project demonstrates how these Objective-C classes can be used to achieve location-based background content to drive discoverability and local engagement.

While one could subclass UIViewController to provide higher orders of abstraction CoreBackground was specifically designed to be loosely coupled and not bound to a particular view hierarchy. This design pattern encourages community modifications and higher adoption rates.
ViewController.m

- (void) viewDidLoad {

    [super viewDidLoad];

    //ScrollView content size
    if([CBGUtil is4InchIphone]) {
        self.scrollView.contentSize = CGSizeMake(320, 720);
    } else {
        self.scrollView.contentSize = CGSizeMake(320, 580);
    }

    //Initial stock photos from bundle
    [[CBGStockPhotoManager sharedManager] randomStockPhoto:^(CBGPhotos * photos) {
        [self crossDissolvePhotos:photos withTitle:@""];
    }];

    //Retrieve location and content from Flickr
    [self retrieveLocationAndUpdateBackgroundPhoto];

    //Schedule updates
    self.timer = [NSTimer scheduledTimerWithTimeInterval:kTimerIntervalInSeconds target:self selector:@selector(retrieveLocationAndUpdateBackgroundPhoto)userInfo:nil repeats:YES];
}

- (void) retrieveLocationAndUpdateBackgroundPhoto {

    //Location
    [[CBGLocationManager sharedManager] locationRequest:^(CLLocation * location, NSError * error) {

        [self.activityIndicator startAnimating];

        if(!error) {

            //Flickr 
            [[CBGFlickrManager sharedManager] randomPhotoRequest:^(FlickrRequestInfo * flickrRequestInfo, NSError * error) {

                if(!error) {
                    self.userPhotoWebPageURL = flickrRequestInfo.userPhotoWebPageURL;

                    [self crossDissolvePhotos:flickrRequestInfo.photos withTitle:flickrRequestInfo.userInfo];
                    [self.activityIndicator stopAnimating];
                } else {

                    //Error : Stock photos
                    [[CBGStockPhotoManager sharedManager] randomStockPhoto:^(CBGPhotos * photos) {
                        [self crossDissolvePhotos:photos withTitle:@""];
                    }];

                    [self.activityIndicator stopAnimating];

                    NSLog(@"Flickr: %@", error.description);
                }
            }];
        } else {

            //Error : Stock photos
            [[CBGStockPhotoManager sharedManager] randomStockPhoto:^(CBGPhotos * photos) {
                [self crossDissolvePhotos:photos withTitle:@""];
            }];

            [self.activityIndicator stopAnimating];

            NSLog(@"Location: %@", error.description);
        }
    }];
}

- (void) crossDissolvePhotos:(CBGPhotos *) photos withTitle:(NSString *) title {
    [UIView transitionWithView:self.backgroundPhoto duration:1.0f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{

        self.backgroundPhoto.image = photos.photo;
        self.backgroundPhotoWithImageEffects.image = photos.photoWithEffects;
        self.photoUserInfoBarButton.title = title;

    } completion:NULL];
}

- (IBAction) launchFlickrUserPhotoWebPage:(id) sender {
    if([self.photoUserInfoBarButton.title  length] > 0) {
        [[UIApplication sharedApplication] openURL:self.userPhotoWebPageURL];
    }
}

- (void) scrollViewDidScroll:(UIScrollView *) scrollView {
    if(scrollView.contentOffset.y >= 0 && scrollView.contentOffset.y <= 80.0) {
        float percent = (scrollView.contentOffset.y / 80.0);

        self.backgroundPhotoWithImageEffects.alpha = percent;

    } else if (scrollView.contentOffset.y > 80.0){
        self.backgroundPhotoWithImageEffects.alpha = 1;
    } else if (scrollView.contentOffset.y < 0) {
        self.backgroundPhotoWithImageEffects.alpha = 0;
    }
}
September 4, 2013 Frameworksframework, ios, objective-c, tutorial

Framework: Mutual Mobile Drawer Controller

Have you ever wanted to build an app with a styled menu that slides out from the left or right like Facebook and YouTube? Now you can easily add this functionality to your apps with a great framework called Mutual Mobile Drawer Controller (MMDrawerController). It was developed by the fine folks at Mutual Mobile.

MMDrawerController is a side drawer navigation container view controller designed to support the growing number of applications that leverage the side drawer paradigm. This library is designed to exclusively support side drawer navigation in a light-weight, focused approach while exposing the ability to provide custom animations for presenting and dismissing the drawer.

Setting up MMDrawerController

Follow the steps below to get started:
1. Visit the GitHub page here:https://github.com/mutualmobile/MMDrawerController.
2. Pull or download the latest version of the source code.
3. Add the following files into your project:
– MMDrawerBarButtonItem.h
– MMDrawerBarButtonItem.m
– MMDrawerController.h
– MMDrawerController.m
– MMDrawerController+Subclass.h
– MMDrawerVisualState.h
– MMDrawerVisualState.m
– UIViewController+MMDrawerController.h
– UIViewController+MMDrawerController.m
4. Include the following header at the top of your App Delegate:
– #import “MMDrawerController.h”
– #import “MMDrawerVisualState.h”
5. Start coding!

Creating a MMDrawerController is as easy as creating a center view controller and the drawer view controllers, and init’int the drawer. Add this to your App Delgate since the drawerController should be your root controller within your app.

@interface MMAppDelegate ()

@property (nonatomic,strong) MMDrawerController * drawerController;

@end

@implementation MMAppDelegate
-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
    UIViewController * leftSideDrawerViewController = [[MMExampleLeftSideDrawerViewController alloc] init];
    
    UIViewController * centerViewController = [[MMExampleCenterTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
    
    UIViewController * rightSideDrawerViewController = [[MMExampleRightSideDrawerViewController alloc] init];
    
    UINavigationController * navigationController = [[UINavigationController alloc] initWithRootViewController:centerViewController];
    [navigationController setRestorationIdentifier:@"MMExampleCenterNavigationControllerRestorationKey"];
    
    self.drawerController = [[MMDrawerController alloc]
                                             initWithCenterViewController:navigationController
                                             leftDrawerViewController:leftSideDrawerViewController
                                             rightDrawerViewController:rightSideDrawerViewController];
    [self.drawerController setRestorationIdentifier:@"MMDrawer"];
    [self.drawerController setMaximumRightDrawerWidth:200.0];
    [self.drawerController setOpenDrawerGestureModeMask:MMOpenDrawerGestureModeAll];
    [self.drawerController setCloseDrawerGestureModeMask:MMCloseDrawerGestureModeAll];
    
    [self.drawerController
     setDrawerVisualStateBlock:^(MMDrawerController *drawerController, MMDrawerSide drawerSide, CGFloat percentVisible) {
         MMDrawerControllerDrawerVisualStateBlock block;
         block = [[MMExampleDrawerVisualStateManager sharedManager]
                  drawerVisualStateBlockForDrawerSide:drawerSide];
         if(block){
             block(drawerController, drawerSide, percentVisible);
         }
     }];
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [self.window setRootViewController:self.drawerController];

    return YES;
}

MMDrawerController is highly customizable. Here’s a quick list of the built in animations:

  • Slide: The drawer slides at the same rate as the center view controller.
  • Slide and Scale: The drawer slides and scales up, while also alpha’ing from 0.0 to 1.0.
  • Swinging Door: The drawer swings in along a hinge on the center view controller.
  • Parallax: The drawer slides in at a slower rate, giving a parallax effect.

There are also some other nice features such as UIGestureRecognizer support, customizable drawer menu button, and a stretch animation effect.

August 28, 2013 Frameworksframework, ios, objective-c, tutorial
Page 1 of 512345»
Recent Posts
  • Classix for iPhone, iPad & Apple TV
  • Tutorial: How to test your app for IPv6 compatibility
  • Tutorial: Testing SSL using Charles Proxy on an iOS Device
  • Tutorial: 3D Touch – Quick Actions in Swift
  • tvOS Tutorial: Top Shelf in Swift
Featured Apps
Classix
Sportsnet
TAGS
tutorialswiftios8iosobjective-cvideogamesstrategynewsframeworkappsmonitizefacebookwatchappleios7toolstvosios9apiprovisionsocialtutorialsbooksdesignbookiapIPv6iTunes Connect
Search
TAGS
tutorialswiftios8iosobjective-cvideogamesstrategynewsframeworkappsmonitizefacebookwatchappleios7toolstvosios9apiprovisionsocialtutorialsbooksdesignbookiapIPv6iTunes Connect
ABOUT
Brian is a Lead iOS/tvOS Developer from Toronto with over 18 years of multifaceted experience including development, design, business analysis and project management.

FOLLOW ME
    
Email Subscription
Sign up for my newsletter to receive the latest news and tutorials posted.

Enter your email address:

2023 © Brian Coleman