Saturday, October 29, 2011

An accelerating magnetic clock?

Sometimes you do stuff just because you can...

I spiffed up my Accelerometer component a little bit. I also wrapped up my Location based stuff into a Location component that handles both GPS coordinates, altitude and heading (true and magnetic).

What better way to test both of these components than my Clock app?

Believe it or not, the time is 11:17am in this screen shot. The 12-hour is pointing North. ;)

And I apparently leaned my phone so that the clock "fell" up into the top-right corner. ;)

Oh, and the second hand is the FireMonkey logo!

Wonder if anyone would buy this thing if I uploaded it as "Clock Pro" and put a $0.99 price tag on it. Source included of course!

CrazyClock

Thursday, October 27, 2011

My first iOS FireMonkey app in the AppStore

Submitted Saturday. Accepted and available tonight!

Anders' Analog Clock

I'll make a video of how it's made, and also publish the source code. Soon.

Enjoy!

First update may very well change the name to "Analog Clock for FireMonkey" just so you can find something in the appstore using "FireMonkey" as the search term. Oh, and properly working iPad support is coming as well. ;)

Please consider checking it out it and rating it! :)

Friday, October 21, 2011

Fix to my CC download for iOS DataSnap

Apparently the .a files I had on my machine are necessary... ;)

If you downloaded the source code from CodeCentral, head on over and download it again for a submission that includes the .a files.

Thursday, October 20, 2011

Fix: Now() returns incorrect time on iOS device, due to a FPC RTL bug

Due to a FPC RTL bug, the Now(), Time() and possibly Date() functions return an incorrect time unless you're actually in GMT.

A possible fix:

var
TZOffsetFromGMT : Integer;

procedure TForm1.FormCreate(Sender: TObject);
begin
TZOffsetFromGMT := NSTimeZone.localTimeZone.secondsFromGMT;
end;

use it later as follows:

var
Hour, Min, Sec, MSec : Word;
CurrTime : TDateTime;
begin
CurrTime := Now+TZOffsetFromGMT/3600.0/24.0;
DecodeTime(CurrTime,Hour,Min,Sec,MSec);

...

end;

Article: DataSnap connectivity for iOS

I have published my article on how to achieve DataSnap connectivity from an iOS application written using Delphi XE2 and FireMonkey!

DataSnap connectivity for iOS using Delphi XE2 and FireMonkey

The article contains a link for the full source in CodeCentral.

Enjoy!

Wednesday, October 12, 2011

iOS demos as videos

Of course CodeRage 6 is around the corner, and I finally recorded my iOS session for it. ;)

I also recorded a 6-minute teaser on "GPS and Compass". It should be posted on YouTube by tomorrow, I hope. I'll blog again when it is.

RAD Studio XE2 World Tour webinar replay available

My World Tour webinar on RAD Studio XE2 is available for replay.

Enjoy!

Monday, October 10, 2011

Getting GPS coordinates and compass heading in an iOS FireMonkey app

GPS and compass in FireMonkey

Below is a code snippet that shows how to write the delegates that get GPS and Compass heading information from the device.

Don't worry - cleaned up complete examples are forthcoming shortly.
{$IFDEF FPC}
type
MyCLController = objcclass(NSObject)
locationManager : CLLocationManager;
procedure locationManager_didUpdateToLocation_fromLocation(manager: CLLocationManager; newLocation, oldLocation: CLLocation); message 'locationManager:didUpdateToLocation:fromLocation:';
procedure locationManager_didUpdateHeading(manager: CLLocationManager; newHeading: CLHeading); message 'locationManager:didUpdateHeading:';
end;

var
Controller : MyCLController;
{$ENDIF}

{$IFDEF FPC}
procedure MyCLController.locationManager_didUpdateToLocation_fromLocation(manager: CLLocationManager; newLocation, oldLocation: CLLocation);
begin
// Do stuff with newLocation.coordinate.latitude and .longitude here
end;
{$ENDIF}

{$IFDEF FPC}
procedure MyCLController.locationManager_didUpdateHeading(manager: CLLocationManager; newHeading: CLHeading);
begin
// Do stuff with newHeading.magneticheading here
end;
{$ENDIF}

procedure TForm1.FormCreate(Sender: TObject);
begin
{$IFDEF FPC}
Controller := MyCLController.alloc.init;
Controller.locationManager := CLLocationManager.alloc.init;
Controller.locationManager.setDelegate(Controller);
Controller.locationManager.startUpdatingLocation;
Controller.locationManager.startUpdatingHeading;
{$ENDIF}
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
{$IFDEF FPC}
Controller.locationManager.release;
Controller.release;
{$ENDIF}
end;

Friday, October 7, 2011

PREVIEW: Delphi iOS FireMonkey DataSnap client!

Find out how at CodeRage 6! October 17-21!

Disclaimer: Super super early preview of hackery done by me, with a LOT of help from Phil Hess. He parsed the ObjC headers for the mobile DataSnap connector. I then used his instructions to compile those header units. After that, I converted 50-70 lines of ObjC for the custom DataSnap access to the custom server methods to get this VERY FIRST demo working. There is no general proxy writer for Delphi/FPC (yet).

Enjoy!

DataSnap on iOS

Thursday, October 6, 2011

Smile! You're on iOS FireMonkey camera!

See you at CodeRage 6!

CameraApp on iOS using Delphi and FireMonkey

Using the Accelerometer in an iOS FireMonkey app

Special thanks to Eugene Kryukov and Phil Hess for this stuff!

Check out CodeRage 6 for a cool implementation!

Enjoy!
implementation

{$R *.lfm}

type
UIAcceleration = objcclass external (NSObject)
public
function timestamp: NSTimeInterval; message 'timestamp';
function x: UIAccelerationValue; message 'x';
function y: UIAccelerationValue; message 'y';
function z: UIAccelerationValue; message 'z';
end;

AccDelegate = objcclass(NSObject)
procedure accelerometer_didAccelerate(accelerometer: UIAccelerometer; acceleration: UIAcceleration); message 'accelerometer:didAccelerate:';
end;

var
AccDelegatVar: AccDelegate;

procedure AccDelegate.accelerometer_didAccelerate(accelerometer: UIAccelerometer; acceleration: UIAcceleration);
begin
// Do whatever you want to with acceleration.x, y and z here!
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
UIAccelerometer.sharedAccelerometer.setUpdateInterval(1.0 / kAccelerometerFrequency);
AccDelegatVar := AccDelegate.alloc;
UIAccelerometer.sharedAccelerometer.setDelegate(AccDelegatVar);
end;

Locking screen rotation in FireMonkey iOS...

Warning: This is a total hack, and should NOT be attempted unless you know exactly what you're doing. I don't know any better, so I just went for it. Editing shipping source files is NEVER supported, encouraged, and shouldn't even be blogged about.

OK, warning aside.

Here we go...

Locate FMX_Platform_iOS.pas on your Mac.

Find this:

function TUIViewController.shouldAutorotateToInterfaceOrientation(
AinterfaceOrientation: UIInterfaceOrientation): Boolean;
begin
Result := True; { HINT! }
end;

Change it. Save it. Done!

PS: Change it to what? Sorry. Not saying... ;)

PPS: You may still have to select supported device orientations in Xcode.

Tuesday, October 4, 2011

Super simple SQLite application for iOS FireMonkey

The following unit creates a table, inserts two records, and queries them back.

Next I'll try to tackle DataSnap... ;)

Enjoy!

unit Unit1;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$modeswitch objectivec1}
{$ENDIF}

interface

uses
SysUtils, Types, UITypes, Classes, Variants, FMX_Types, FMX_Controls, FMX_Forms,
FMX_Dialogs, FMX_Layouts, FMX_Memo
{$IFDEF FPC}
, iPhoneAll, SQLite3db, SQLite
{$ENDIF}
;

type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.lfm}

procedure Log(Msg : String);
begin
{$IFDEF FPC}
NSLog(NSSTR(PChar(Msg)));
{$ENDIF}
end;

{$IFDEF FPC}
function MyDirectory : NSString;
var
paths : NSArray;
fileName : NSString;
begin
paths := NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, True);
fileName := paths.objectAtIndex(0);
Result := fileName;
end;
{$ENDIF}

procedure TForm1.Button1Click(Sender: TObject);
{$IFDEF FPC}
var
FileName, SQL : String;
DB : TSQLite;
SL : Classes.TStringList;
{$ENDIF}
begin
{$IFDEF FPC}
FileName := String(MyDirectory.UTF8String)+'/MyDB.sqlite';
Log(FileName);

DB := TSQLite.Create(FileName);

(*
// Drop the table and start from scratch
SQL := 'drop table Customers';
DB.Query(SQL,nil);
*)

// Create the table
SQL := 'create table Customers (Id integer not null, LastName char(25), FirstName char(25))';
DB.Query(SQL,nil);

// Insert a couple of records
SQL := 'insert into Customers values(1, "Ohlsson", "Anders")';
DB.Query(SQL,nil);
SQL := 'insert into Customers values(2, "Intersimone", "David")';
DB.Query(SQL,nil);

// Get the records back and list them in the memo
SL := Classes.TStringList.Create;
SQL := 'select * from Customers';
if DB.Query(SQL,SL) then
Memo1.Text := SL.Text;
SL.Free;

DB.Free;
{$ENDIF}
end;

end.

Reading and writing files from an iOS FireMonkey application

Here's an example of how you can read and write files in your iOS FireMonkey application.

Enjoy!


{$IFDEF FPC}
var
content : NSString;
{$ENDIF}

{$IFDEF FPC}
function MyFileName : NSString;
var
paths : NSArray;
fileName : NSString;
begin
paths := NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, True);
fileName := paths.objectAtIndex(0);
fileName.stringByAppendingString(NSSTR(PChar('/myfile.txt')));
Result := fileName;
end;
{$ENDIF}

procedure TForm1.Button1Click(Sender: TObject);
begin
// Write to file
{$IFDEF FPC}
Label2.Text := 'Wrote to: '+String(MyFileName.UTF8String);
content := NSSTR(PChar(String(Memo1.Text)));
content.writeToFile_atomically_encoding_error(MyFileName,False,NSStringEncodingConversionAllowLossy,nil);
content.release;
{$ENDIF}
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
// Read from file
{$IFDEF FPC}
Label2.Text := 'Read from '+String(MyFileName.UTF8String);
content.InitWithContentsOfFile_usedEncoding_error(MyFileName,nil,nil);
Memo1.Text := String(content.UTF8String);
content.release;
{$ENDIF}
end;

Toggling the Status Bar using an iOS FireMonkey application

Q: How do I turn on/off the Status Bar on the iPhone?
A: By calling setStatusBarHidden

Below, a simple unit that shows how to toggle the status bar using different animations - none, fade, and slide. The example also shows how to toggle the network activity indicator.

unit Unit1;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$modeswitch objectivec1}
{$ENDIF}

interface

uses
SysUtils, Types, UITypes, Classes, Variants, FMX_Types, FMX_Controls, FMX_Forms,
FMX_Dialogs
{$IFDEF FPC}
, iPhoneAll
{$ENDIF}
;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
{$IFDEF FPC}
UIApplication.sharedApplication.setStatusBarHidden(not UIApplication.sharedApplication.isStatusBarHidden);
{$ENDIF}
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
{$IFDEF FPC}
UIApplication.sharedApplication.setStatusBarHidden_withAnimation(not UIApplication.sharedApplication.isStatusBarHidden,UIStatusBarAnimationFade);
{$ENDIF}
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
{$IFDEF FPC}
UIApplication.sharedApplication.setStatusBarHidden_withAnimation(not UIApplication.sharedApplication.isStatusBarHidden,UIStatusBarAnimationSlide);
{$ENDIF}
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
{$IFDEF FPC}
UIApplication.sharedApplication.setNetworkActivityIndicatorVisible(not UIApplication.sharedApplication.isNetworkActivityIndicatorVisible);
{$ENDIF}
end;

end.

Manipulating the icon badge numbers from an iOS FireMonkey application

Q: How do I update those little numeric indicators on my app's icon to show how many notifications the user should have?
A: By using setApplicationIconBadgeNumber

Very simple unit that increments the icon badge number below.

Enjoy!

unit Unit1;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$modeswitch objectivec1}
{$ENDIF}

interface

uses
SysUtils, Types, UITypes, Classes, Variants, FMX_Types, FMX_Controls, FMX_Forms,
FMX_Dialogs
{$IFDEF FPC}
, iPhoneAll
{$ENDIF}
;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
{$IFDEF FPC}
UIApplication.sharedApplication.setApplicationIconBadgeNumber(UIApplication.sharedApplication.applicationIconBadgeNumber+1);
{$ENDIF}
end;

end.

Sending an email from an iOS FireMonkey application

Q: How do you send an email from the iPhone using FireMonkey?
A: By opening a mailto URL

Below is a very simple unit that will do the trick. Just create a brand new iOS FireMonkey application, and add two edit boxes and one memo. The first edit box will hold the email address we're sending the email to. The second edit box will contain the subject line, and the memo will contain the actual email body.

Notice that this opens the local email client and you have to send it manually. It does *not* send the email in the background.

Enjoy!

unit Unit1;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$modeswitch objectivec1}
{$ENDIF}

interface

uses
SysUtils, Types, UITypes, Classes, Variants, FMX_Types, FMX_Controls, FMX_Forms,
FMX_Dialogs, FMX_Layouts, FMX_Memo, FMX_Edit
{$IFDEF FPC}
, iPhoneAll
{$ENDIF}
;

type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Label1: TLabel;
Edit2: TEdit;
Label2: TLabel;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.Button1Click(Sender: TObject);
var
ToStr, SubjectStr, BodyStr : String;
URL : NSString;
begin
{$IFDEF FPC}

ToStr := Edit1.Text;
SubjectStr := Edit2.Text;
BodyStr := Memo1.Text;

URL := NSSTR(PChar('mailto:'+ToStr+'?subject='+SubjectStr+'&body='+BodyStr));
URL := URL.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding);

UIApplication.sharedApplication.openUrl(NSURL.URLWithString(URL));
{$ENDIF}
end;

end.

Getting directions from an iOS FireMonkey application

Q: How do you get directions on the iPhone from a FireMonkey application?
A: By opening a URL formatted like so - http://maps.google.com/maps?saddr=FROM&daddr=TO

unit Unit1;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$modeswitch objectivec1}
{$ENDIF}

interface

uses
SysUtils, Types, UITypes, Classes, Variants, FMX_Types, FMX_Controls, FMX_Forms,
FMX_Dialogs
{$IFDEF FPC}
, iPhoneAll
{$ENDIF}
;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.Button1Click(Sender: TObject);
var
LocationFrom, LocationTo, URL : String;
begin
{$IFDEF FPC}
LocationFrom := 'Current+Location';
LocationTo := 'Scotts+Valley+Drive,+Scotts+Valley,+CA';
URL := 'http://maps.google.com/maps?saddr='+LocationFrom+'&daddr='+LocationTo;
UIApplication.sharedApplication.openUrl(NSUrl.URLWithString(NSSTR(PChar(URL)))));
{$ENDIF}
end;

end.

Display a map from an iOS FireMonkey application

Q: How do you display a map on the iPhone using FireMonkey?
A: By opening a URL formatted like so - http://maps.google.com/maps?q=LOCATION

Below is a short snippet that will do show a map of the Embarcadero Scotts Valley offices.

Enjoy!

unit Unit1;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$modeswitch objectivec1}
{$ENDIF}

interface

uses
SysUtils, Types, UITypes, Classes, Variants, FMX_Types, FMX_Controls, FMX_Forms,
FMX_Dialogs
{$IFDEF FPC}
, iPhoneAll
{$ENDIF}
;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.Button1Click(Sender: TObject);
var
Location : String;
begin
{$IFDEF FPC}
Location := 'http://maps.google.com/maps?q=5617+Scotts+Valley+Drive,+Scotts+Valley,+CA';
UIApplication.sharedApplication.openUrl(NSUrl.URLWithString(NSSTR(PChar(Location))));
{$ENDIF}
end;

end.

Opening a URL from an iOS FireMonkey application

Q: How do you open a URL in Safari on the iPhone using FireMonkey?
A: You use UIApplication.sharedApplication.openUrl

Below is a very simple unit that will do the code. Just create an iOS app with one button and add the following code to the unit.

unit Unit1;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$modeswitch objectivec1}
{$ENDIF}

interface

uses
SysUtils, Types, UITypes, Classes, Variants, FMX_Types, FMX_Controls, FMX_Forms,
FMX_Dialogs
{$IFDEF FPC}
, iPhoneAll
{$ENDIF}
;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
// Open a URL
{$IFDEF FPC}
UIApplication.sharedApplication.openUrl(NSUrl.URLWithString(NSSTR(PChar('http://blogs.embarcadero.com/ao'))));
{$ENDIF}
end;

end.

Dialing a phone number from an iOS FireMonkey application

Q: How do you dial a phone number from an iOS application?
A: You open a URL with the following format - tel://123456789

Below is a very simple Delphi iOS unit that will do the trick.

Notice the {$IFDEF FPC} blocks that ensure that the application also compiles and is "testable" on Windows.

Enjoy!
unit Unit1;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$modeswitch objectivec1}
{$ENDIF}

interface

uses
SysUtils, Types, UITypes, Classes, Variants, FMX_Types, FMX_Controls, FMX_Forms,
FMX_Dialogs
{$IFDEF FPC}
, iPhoneAll
{$ENDIF}
;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
// Dial a phone number
{$IFDEF FPC}
UIApplication.sharedApplication.openUrl(NSUrl.URLWithString(NSSTR(PChar('tel://18005551212'))));
{$ENDIF}
end;

end.

Thursday, September 29, 2011

FireMonkey performance on iOS device 2x-3x FASTER with Update 1

Great news!

FireMonkey iOS apps built with the RTM version of RAD Studio XE2 were a little sluggish. The great news is that with Update 1 that was just released, the performance has improved significantly!

We will of course continue updating and improving performance wherever possible as soon as possible.

Get Update 1 here.

Enjoy!

Tuesday, September 6, 2011

My RAD Studio XE2 Launch Stops

The RAD Studio XE2 World Tour is in full swing. All the stops are listed here.

I launched the new product in Orange County and Los Angeles last week, and the feedback has been amazing! The sign-ups for the events is close to double from what it was last year, and people are very impressed with what we've packed into this release!

It's pure joy showing off 64-bit, FireMonkey, MacOSX, iOS, VCL Styles, LiveBindings, etc, etc!

Here's the rest of my schedule:

9/7 Portland, OR
9/8 Seattle, WA
9/12-14 Delphi Live
9/15 San Diego, CA
9/17 Washington, DC
9/20 Salt Lake City, UT
9/21 Phoenix, AZ
9/22 Sacramento, CA
9/24 Newark, NJ

Enjoy! :)

Thursday, June 23, 2011

AppWave is here!

AppWave is your private PC app store that provides a mobile-like experience for Windows software. Learn how it can help you boost productivity.

Productivity is increased. Friction is eliminated. Discovering and launching apps is simple and quick.


AppWave is a free, enterprise-grade private PC app store that provides a mobile-like app experience for PC software applications. With AppWave, you can quickly discover and run PC apps. Say goodbye to desktop software installations, manual upgrade processes, and confusing license tracking. Now anyone can experience PC apps the way they should be. Friction-free.

Surf the AppWave here!