I wanted to collect usage statistics from the users of my iPhone applications. The information Apple collects about free vs paid downloads is interesting, but a little hard to analyze. I wanted to see how much information I could collect, as well as run my own custom queries against a database of statistical information.
In order to do this, I set up a MySQL database online, with a PHP script to enter data into the database. Then I added some code to my main appDelegate.m file to check to see if there was an internet connection, and if so, send the device information. The PHP script then checks the database to see if that device is already in the database and if not, adds it. If it was in the database already, it just increments the number of accesses.
MySQL code
The following are the tables that need to be created within a MySQL database to store the information that you will be collecting.
CREATE TABLE IF NOT EXISTS `TableDevices` (
`intDeviceID` int(11) NOT NULL auto_increment,
`strDeviceName` tinytext NOT NULL,
`strDeviceModel` tinytext NOT NULL,
`strDeviceLocalizedModel` tinytext NOT NULL,
`strDeviceSystemName` tinytext NOT NULL,
`strDeviceSystemVersion` tinytext NOT NULL,
`strDeviceUniqueIdentifier` tinytext NOT NULL,
`intTotalUpdates` int(11) NOT NULL,
`dateCreated` datetime NOT NULL,
`dateUpdated` datetime NOT NULL,
`strIPCreated` tinytext NOT NULL,
`strIPUpdated` tinytext NOT NULL,
PRIMARY KEY (`intDeviceID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
PHP code
(You will need to change DATABASE_USER_NAME, DATABASE_USER_PASSWORD, and DATABASE_NAME below to the appropriate values for your MySQL server instance.)
<?
mysql_connect ("localhost", "DATABASE_USER_NAME",
"DATABASE_USER_PASSWORD");
mysql_select_db ("DATABASE_NAME");
$dateCreated = date ("Y-m-d H:i:s");
$strIPCreated = $_SERVER[REMOTE_ADDR];
function cleanString ($strInput) {
$strInput = trim(strip_tags ($strInput));
return (mysql_real_escape_string ($strInput));
}
$_POST[a] = cleanString ($_POST[a]);
$_POST[b] = cleanString ($_POST[b]);
$_POST[c] = cleanString ($_POST[c]);
$_POST[d] = cleanString ($_POST[d]);
$_POST[e] = cleanString ($_POST[e]);
$_POST[f] = cleanString ($_POST[f]);
$qry = mysql_query ("SELECT intDeviceID, intTotalUpdates
FROM TableDevices WHERE strDeviceUniqueIdentifier = '$_POST[f]'");
if ($qry != "" && mysql_num_rows ($qry) > 0) {
$arr = mysql_fetch_array ($qry);
$intTotalUpdates = $arr[intTotalUpdates] + 1;
$intDeviceID = $arr[intDeviceID];
$qry2 = mysql_query ("UPDATE TableDevices
SET
strDeviceName = '$_POST[a]',
strDeviceModel = '$_POST[b]',
strDeviceLocalizedModel = '$_POST[c]',
strDeviceSystemName = '$_POST[d]',
strDeviceSystemVersion = '$_POST[e]',
dateUpdated = '$dateCreated',
strIPUpdated = '$strIPCreated',
intTotalUpdates = '$intTotalUpdates'
WHERE
intDeviceID = '$intDeviceID'");
} else {
$qry2 = mysql_query ("INSERT INTO TableDevices (
strDeviceName,
strDeviceModel,
strDeviceLocalizedModel,
strDeviceSystemName,
strDeviceSystemVersion,
strDeviceUniqueIdentifier,
dateCreated,
strIPCreated,
intTotalUpdates
) VALUES (
'$_POST[a]',
'$_POST[b]',
'$_POST[c]',
'$_POST[d]',
'$_POST[e]',
'$_POST[f]',
'$dateCreated',
'$strIPCreated',
'1'
)"); }
echo "1";
?>
iPhone Code
Based on a View Controller application template, the following would need to be added to the main AppDelegate.m file.
You will need to change the host_naem and the strDeviceStatPath below to be whatever your web server addresses are.
NOTE: You'll also need to add the SystemConfiguration.framework to the list of frameworks in your iPhone application!
#import <SystemConfiguration/SystemConfiguration.h>
const char *host_name = "www.site.com";
const char *strDeviceStatPath = "http://www.site.com/appname/stats.php";
NSMutableURLRequest *urlRequest;
BOOL _isDataSourceAvailable = NO;
- (BOOL) isDataSourceAvailable {
static BOOL checkNetwork = YES;
if (checkNetwork) {
checkNetwork = NO;
Boolean success;
SCNetworkReachabilityRef reachability =
SCNetworkReachabilityCreateWithName(NULL, host_name);
SCNetworkReachabilityFlags flags;
success = SCNetworkReachabilityGetFlags(reachability, &flags);
_isDataSourceAvailable = success
&& (flags & kSCNetworkFlagsReachable)
&& !(flags & kSCNetworkFlagsConnectionRequired);
CFRelease(reachability);
}
return _isDataSourceAvailable;
}
-(void) sendUsageStatistics {
UIDevice *device = [UIDevice currentDevice];
NSString *myRequestString = [NSString
stringWithFormat:@"a=%@&b=%@&c=%@&d=%@&e=%@&f=%@",
device.name, device.model, device.localizedModel,
device.systemName, device.systemVersion, device.uniqueIdentifier];
NSData *myRequestData = [ NSData
dataWithBytes:[ myRequestString UTF8String ]
length: [ myRequestString length ] ];
urlRequest = [ [ NSMutableURLRequest alloc ]
initWithURL:[ NSURL URLWithString:
[NSString stringWithFormat:@"%s", strDeviceStatPath] ] ];
[urlRequest setValue:@"application/x-www-form-urlencoded"
forHTTPHeaderField:@"content-type"];
[urlRequest setHTTPMethod: @"POST"];
[urlRequest setHTTPBody: myRequestData];
NSData *returnData = [NSURLConnection
sendSynchronousRequest:urlRequest
returningResponse:nil error:nil];
returnData = nil;
}
- (void)applicationDidFinishLaunching:(UIApplication *)application {
if ([self isDataSourceAvailable] == YES) {
[self sendUsageStatistics];
}
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
And that's it! It's a little complicated to set up at first, but once you have it set up, you'll be able to collect some very interesting data on how many people are using your application, as well as how often they use it. This can also be extended to save total playing time, "hits" on different views within your application, or anything else that can help you make your application more usable (or help debug where people seem to be getting stuck...
1 Comments
| |
|
02
Jul 2009
|
Alexandra Asselin Hernandez Very smart you are..... |
Submit a Comment: