Developing Xcode 4 Plugins

This is a quick guide that documents how to start developing plugins for Xcode4. You need to have Xcode installed to create plugins.

Step 1 – Xcode Plugin Project Template

  • Grab the Xcode project template for creating plugins from here
  • Create the plugin template folder ~/Library/Developer/Xcode/Templates/Project Templates/Application Plug-in/Xcode4 Plugin.xctemplate if it doesn’t already exist.
  • A quick way to do this is with the following command mkdir -p "~/Library/Developer/Xcode/Templates/Project Templates/Application Plug-in/Xcode4 Plugin.xctemplate"
  • Copy the contents of the GitHub repository to the folder you just created.
  • Restart Xcode.

Step 2 – Create a test project

  • Open Xcode, and select File > New > Project
  • Then under OS X > Templates tap Xcode4 Plugin (shown below)

Screen Shot 2013-04-29 at 3.44.05 PM

From the GitHub repo:

The default plugin file links against AppKit and Foundation, and, when built 
(and Xcode is restarted), creates a menu item labeled "Do Action" in the File menu. 
Pressing the menu item should open an alert. Customize at will!

If we run the project we just created, it will automatically build and copy the plugin to the right location. In this case it is ~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/[Project Name].xcplugin. Restarting Xcode, we get a new menu item under the File menu!

Screen Shot 2013-04-29 at 3.53.02 PM

When we click on the menu item, we get an alert:

Screen Shot 2013-04-29 at 3.53.49 PM

Notes:

  • Xcode plugins have to be written using Objective-C GC, this means you have to use retain and release calls in your code. (No ARC support).

Where to go from here?

  • This StackOverflow answer has some great ideas on where to go next.
  • You can get a dump of the private headers that Xcode uses by using the class-dump tool
  • brew install class-dump is the quickest way to get it if you have homebrew installed.
  • IDEKit and IDEFoundation are present at Xcode.app/Contents/Frameworks
  • DVTKit and DVTFoundation are present at Xcode.app/Contents/SharedFrameworks
  • By registering an observer for nil you can see all the notifications that are being called. This is useful to find out which actions are called and when, and what notifications you might need to listen for.
Advertisements

Gradient background for UIView in iOS

One of the pieces of code I find myself re-using constantly is creating a gradient background for a UIView in iOS. This example will show two examples of how to create a simple gradient background.

First, in Xcode, create a new Single View iOS application

Then create a new file File > New > New File and call this file “BackgroundLayer”, this will create BackgroundLayer.h and BackgroundLayer.m automatically for you.

Then copy the following code into the BackgroundLayer.h header file



#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>

@interface BackgroundLayer : NSObject

+(CAGradientLayer*) greyGradient;
+(CAGradientLayer*) blueGradient;

@end

Then copy the following code into the BackgroundLayer.m file



#import "BackgroundLayer.h"

@implementation BackgroundLayer

//Metallic grey gradient background
+ (CAGradientLayer*) greyGradient {

    UIColor *colorOne = [UIColor colorWithWhite:0.9 alpha:1.0];
    UIColor *colorTwo = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.85 alpha:1.0];
    UIColor *colorThree     = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.7 alpha:1.0];
    UIColor *colorFour = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.4 alpha:1.0];

    NSArray *colors =  [NSArray arrayWithObjects:(id)colorOne.CGColor, colorTwo.CGColor, colorThree.CGColor, colorFour.CGColor, nil];

    NSNumber *stopOne = [NSNumber numberWithFloat:0.0];
    NSNumber *stopTwo = [NSNumber numberWithFloat:0.02];
    NSNumber *stopThree     = [NSNumber numberWithFloat:0.99];
    NSNumber *stopFour = [NSNumber numberWithFloat:1.0];

    NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, stopThree, stopFour, nil];
    CAGradientLayer *headerLayer = [CAGradientLayer layer];
    headerLayer.colors = colors;
    headerLayer.locations = locations;

    return headerLayer;

}

//Blue gradient background
+ (CAGradientLayer*) blueGradient {

    UIColor *colorOne = [UIColor colorWithRed:(120/255.0) green:(135/255.0) blue:(150/255.0) alpha:1.0];
    UIColor *colorTwo = [UIColor colorWithRed:(57/255.0)  green:(79/255.0)  blue:(96/255.0)  alpha:1.0];

    NSArray *colors = [NSArray arrayWithObjects:(id)colorOne.CGColor, colorTwo.CGColor, nil];
    NSNumber *stopOne = [NSNumber numberWithFloat:0.0];
    NSNumber *stopTwo = [NSNumber numberWithFloat:1.0];

    NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, nil];

    CAGradientLayer *headerLayer = [CAGradientLayer layer];
    headerLayer.colors = colors;
    headerLayer.locations = locations;

    return headerLayer;

}

@end

Then finally, in your ViewController #import “BackgroundLayer.h” and add the following code to the viewWillAppear method:



CAGradientLayer *bgLayer = [BackgroundLayer blueGradient];
bgLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:bgLayer atIndex:0];

And don’t forget to add the QuartzCore framework to your project.

Run the project and you get a result like this:


Click here to download the project

Edit: Thanks to moi in the comments below, add the following code to your view controller so that the CALayer rotates with the view



- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    // resize your layers based on the view’s new bounds
    [[[self.subview.layer sublayers] objectAtIndex:0] setFrame:self.subview.bounds];
}

Getting Box2D Physics Working in Xcode

Here is an easy way to get up and running with Box2D in Xcode 3.2. I recently had to install Box2D and thought I might share my method for installing and creating an example Xcode project.

First, If you haven’t already got it, download MacPorts from this website as this makes installing libraries a breeze – http://www.macports.org/

Next, open up a terminal and type “sudo port install box2d”
This command downloads and starts to install the box2d libraries. The default installation places the library files in /opt/local/lib and the header files in /opt/local/include.

Once the install has finished, open up a new Xcode project and choose Application > Command Line Tool > c++ stdc++

Next, we are going to add the include and header search paths. In the top menu click Project -> Edit Active Target -> Build and under the search paths heading change the header search path to /opt/local/include and the library search path to /opt/local/lib. Note: DON’T set the recursive checkbox to true. I had problems with this, so it’s probably best to avoid it.

In the same window, click on the General tab and add a file to the “Linked Libraries” Click “add other” and navigate to /opt/local/lib/libBox2D.a

Finally, add the hello world source (this is from the original distribution)



/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/

#include <Box2D/Box2D.h>
#include <cstdio>

// This is a simple example of building and running a simulation
// using Box2D. Here we create a large ground box and a small dynamic
// box.
// There are no graphics for this example. Box2D is meant to be used
// with your rendering engine in your game engine.

int main(int argc, char** argv)
{
B2_NOT_USED(argc);
B2_NOT_USED(argv);

// Define the gravity vector.
b2Vec2 gravity(0.0f, -10.0f);

// Do we want to let bodies sleep?
bool doSleep = true;

// Construct a world object, which will hold and simulate the rigid bodies.
b2World world(gravity, doSleep);

// Define the ground body.
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0.0f, -10.0f);

// Call the body factory which allocates memory for the ground body
// from a pool and creates the ground box shape (also from a pool).
// The body is also added to the world.
b2Body* groundBody = world.CreateBody(&groundBodyDef);

// Define the ground box shape.
b2PolygonShape groundBox;

// The extents are the half-widths of the box.
groundBox.SetAsBox(50.0f, 10.0f);

// Add the ground fixture to the ground body.
groundBody->CreateFixture(&groundBox, 0.0f);

// Define the dynamic body. We set its position and call the body factory.
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(0.0f, 4.0f);
b2Body* body = world.CreateBody(&bodyDef);

// Define another box shape for our dynamic body.
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(1.0f, 1.0f);

// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;

// Set the box density to be non-zero, so it will be dynamic.
fixtureDef.density = 1.0f;

// Override the default friction.
fixtureDef.friction = 0.3f;

// Add the shape to the body.
body->CreateFixture(&fixtureDef);

// Prepare for simulation. Typically we use a time step of 1/60 of a
// second (60Hz) and 10 iterations. This provides a high quality simulation
// in most game scenarios.
float32 timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;

// This is our little game loop.
for (int32 i = 0; i GetPosition();
float32 angle = body->GetAngle();

printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle);
}

// When the world destructor is called, all bodies and joints are freed. This can
// create orphaned pointers, so be careful about your world management.

return 0;
}

That’s it! Compile and have fun! Check out the box2d project on google code for other examples and documentation – http://code.google.com/p/box2d/