[JSON] La specifica JSON-RPC 2.0: alcuni client iOs


masthead-jsonrpc2base
Esiste una specifica alquanto diffusa per la distribuzione di servizi RESTful, con l’ovvio formato di interscambio JSON, nota come JSON-RPC 2.0.

Pe le caratteristiche di dettaglio di questa specifica vi rimando al sito ufficiale: http://www.jsonrpc.org/specification 

In breve, JSON-RPC non è altro che un protocollo per la chiamata di procedure remote, dove è possibile passare al servizio anche oggetto complessi ed avere in output dati multipli. La descrizione del servizio (una sorta di WSDL) è ben definita, come anche i codici di errore e di successo restituiti dalla chiamata. In sintesi, non è altro che un “modo” per la scrittura di servizi RESTful secondo un certo standard.

La cosa interessante è che il servizio remoto viene interrogato tramite i comuni protocolli HTTP o TCP/IP e la serializzazione degli oggetti di output avviene in formato JSON. Una richiesta di servizio è una chiamata a un metodo specifico e che contiene le seguenti proprietà:

  • method – una stringa con il nome del metodo da invocare.
  • params – un array di oggetti da passare come parametri al metodo definito.
  • id un valore di qualsiasi tipo, che viene utilizzato per abbinare la risposta alla richiesta

Esempio:  {“jsonrpc”: “2.0”, “method”: “subtract”, “params”: [42, 23], “id”: 1}

json-rpc2.0 Per poter richiamare questi servizi da un’app mobile iOs, ho provato i seguenti client:

Esiste anche la possibilità di richiamare i servizi JSON-RPC in “modalità nativa”, come descritto da questo tutorial:

Nel mercato delle app mobile, a non guadagnare saranno gli sviluppatori

In un post pubblicato a novembre scorso, esprimevo il mio parere circa le potenzialità/possibilità di guadagnare nel mercato delle app mobile:

l Freemium: Le app economiche potrebbero uccidere l’App Store

Stavolta riporto un pò di dati alla mano, citando un articolo pubblicato su Wired di Marzo 2014:

Con le app non si diventa ricchi

Sei un giovane smanettone in cerca di successo? Per fare soldi non ha senso pensare a una nuova app. Secondo un report di Gartner, una delle società leader nella consulenza e nell’analisi del mondo dell’Information Technology, nel 2018 solo lo 0,01% di questi software sarà anche un successo finanziario.

Nella guerra tra i marketplace che si sta consumando questa primavera, con l’offerta di Android Market che dovrebbe toccare quota 1 milione entro giugno superando iTunes Store, a non guadagnare un soldo saranno proprio gli sviluppatori. I download non significano successo finanziario: le previsioni indicano nel 94,5% la quota di applicazioni che nel 2017 saranno scaricabili gratis. Per avere probabilità di successo, sottolinea Gartner, bisogna puntare su grandi spese pubblicitarie o avere un brand già molto forte.

Per quanto riguarda le app a pagamento, già oggi il 90% è scaricato meno di 500 volte al giorno: una soglia che non permette di raggiungere la redditività finanziaria. Le previsioni indicano un ulteriore aumento dell’aggressività di un mercato già definito iperattivo. Le piattaforme per la produzione di app sono, da sole, oltre 200, in gran parte basate su strumenti open. E il loro numero
è destinato a crescere ancora.

[http://www.wired.it/economia/lavoro/2014/04/03/con-le-app-non-si-diventa-ricchi/]

 

[AppMobile] iParcheggiatori

iparcheggiatoriApplicazione Mobile: iParcheggiatori

Pagina Store: Apple Store

Sito web: http://www.iparcheggiatori.it

Descrizione: App per la segnalazione dei “parcheggiatori abusivi”. L’idea è quella di sfruttare la tecnologia per “stanare” questi estorsori in piena regola. Nasce così iParcheggiatori, un’applicazione gratuita che permette di inviare segnalazioni “Anonime” da qualsiasi punto d’Italia in cui ci si trovi.
Il sistema, attraverso la geolocalizzazione, permette di indicare il punto esatto della città in cui sono presenti i parcheggiatori abusivi. E’ possibile, in aggiunta, indicare se il pagamento è “a piacere” (ossia una somma da contrattare con il “lavoratore” di turno) e se qualcuno abbia subito minacce o danni alla propria vettura.

Requisiti: Richiede l’iOS 5.1.1 o successive. Compatibile con iPhone, iPad e iPod touch. Questa app è ottimizzata per iPhone 5.

Categoria: Utility

Tecnologie: XCode 5; iPhone 3GS/4/4S/5/5S; MacOx 10.9 (Maverick) – Linguaggio: Objective-C; Framework e Librerie: MapKit; Integrazione con servizi REST-JSON.

Creative Commons License
This work by Francesco Ficetola is licensed under a Creative Commons Attribution 4.0 International License.
Based on a work at www.francescoficetola.it.
Permissions beyond the scope of this license may be available at http://www.francescoficetola.it/2014/02/22/appmobile-iparcheggiatori/.

[iOs] Upload di immagini da app su server

Come primo post dell’anno, vi scrivo una soluzione per l’upload di foto su un vostro server (valida anche per qualsiasi altro tipo di file). Fino a poco tempo fa era possibile utilizzare il framework ASIHTTPRequest, che permetteva in modo agevole di eseguire questa operazione. Tuttavia, essendo tale framework “no-ARC compatibile”, vi consiglio un metodo nuovo che sfrutta la classe “nativa” NSURLConnection, oppure la libreria di terza parte URLConnection (per inserire una comoda progress bar).

Vi scrivo anche lo script PHP da richiamare lato app per l’upload della foto e che ho utilizzato come test (file image_upload.php):

/* image_upload.php */

<?php

//elenco delle estensioni permesse
$extensions_permitted = array("jpg", "png", "JPG", "PNG");

//path assoluto in cui si trova il file di script upload_image.php
$absolute_current_path = getcwd();

//recupero il nome del file dal parametro di input "filename"
$filename = $_POST['filename'];
$response = array();
$error = false;

//recupero l'estensione del file
$ext = pathinfo($_FILES['userfile']['name'], PATHINFO_EXTENSION);

//controllo il nome file
if(empty($filename)){
  $error = true;
  $response['code'] = '500';	
  $response['message'] = ('Nome file non valido!');	
  $response['newfile'] = $filename.'.'.$ext;
}

//controllo l'estensione
if (!in_array($ext, $extensions_permitted)) {
  $error = true;
  $response['code'] = '500';	
  $response['message'] = ('Estensione del file non permessa!');	
  $response['newfile'] = null;
}

if(!$error){
	//NOTA: la seguente directory deve esistere sul proprio server.
	//Assicurarsi di avere i chmod di scrittura
	$uploaddir = $absolute_current_path.'/img/';

	//percorso assoluto del nuovo file
	$uploadfile = $uploaddir . $filename.'.'.$ext;

	if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
    	$response['code'] = '200';	
  		$response['message'] = ('File valido e correttamente salvato!');	
        $response['newfile'] = $filename.'.'.$ext;
	} else {
    	echo "Errore nell'upload del file!\n";
        $response['code'] = '500';	
  		$response['message'] = ('Errore nell\'upload del file!');	
        $response['newfile'] = null;
	}

//echo 'Alcune informazioni di debug:';
//print_r($_FILES);

}

echo json_encode($response);

?>

Di seguito, una pagina di test PHP per controllare che il vostro script di upload sia stato configurato correttamente sul vostro server. NOTA. Vi troverete le immagini nella directory IMG relativa al file image_upload.php.

<html>
<head>
	<title>Upload a file</title>
</head>

<body>
<!-- Tipo di codifica dei dati, DEVE essere specificato come segue -->
<form enctype="multipart/form-data" action="upload_image.php" method="POST">

    <!-- MAX_FILE_SIZE deve precedere campo di input del nome file -->
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" />

    <b>Nome file:</b>
    <input type="text" name="filename" value="" />

    <br/>

    <!-- Il nome dell'elemento di input determina il nome nell'array $_FILES -->
    <b>File:</b> <input name="userfile" type="file" />
    <br/>
    <input type="submit" value="Invia File" />
</form>

</body>

</html>

Ecco i codici sorgenti degli script PHP su riportati:

PHP upload script

upload
upload.rar (2 kB)

Template doesn't exists. Use default

Passiamo ora al codice Objective-C per la vostra app client. Ho creato la classe UploaderDelegate, che potete comodamente importare nei vostri progetti e che gestirà l’upload della foto. L’interfaccia è quella che segue:

//
//  UploaderDelegate.h
//
//  Created by Fr@nk on 07/01/14.
//  Copyright (c) 2014. All rights reserved.
//

#import <Foundation/Foundation.h>

@protocol UploaderProtocol <NSObject>

@required
-(void)successUpload;

@optional
-(void)unsuccessUpload;

@optional
-(void)updateProgressBar:(float)progress;

@end

@interface UploaderDelegate : NSObject<NSURLConnectionDataDelegate>{

    NSMutableData *receivedData;

}

//singleton
+ (id)sharedInstance;
-(void)sendImageToServerWithURLPath:(NSString*)pathImage withFilename:(NSString*)filename toServiceURL:(NSString*)serviceURL;

@property (nonatomic, weak) id<UploaderProtocol> delegate;

@end

L’implementazione dell’UploadDelegate è questa:

//
//  UploaderDelegate.m
//
//  Created by Fr@nk on 07/01/14.
//  Copyright (c) 2013. All rights reserved.
//

#import "UploaderDelegate.h"
#import "URLConnection.h"
#import "Configuration.h"

@implementation UploaderDelegate

@synthesize delegate;

static UploaderDelegate *sharedInstance = nil;

// Get the shared instance and create it if necessary.
+ (UploaderDelegate *)sharedInstance {
    if (sharedInstance == nil) {
        sharedInstance = [[super allocWithZone:NULL] init];
    }

    return sharedInstance;
}

- (id)init
{
    self = [super init];

    if (self) {

    }

    return self;
}

-(void)sendImageToServerWithURLPath:(NSString*)pathImage withFilename:(NSString*)filename toServiceURL:(NSString*)serviceURL{

    //controllo se il file esiste
    BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:pathImage];

    if(!fileExists){
        NSLog(@"Error: file not exists!");
        //richiamo l'errorUpload sul Delegate in caso di success
        if (self.delegate && [self.delegate respondsToSelector:@selector(unsuccessUpload)]) {
            [self.delegate unsuccessUpload];
        }
        return;
    }

    //controllo la grandezza del file
    NSError *AttributesError = nil;
	NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:pathImage error:&AttributesError];
	NSNumber *fileSizeNumber = [fileAttributes objectForKey:NSFileSize];
	long fileSize = [fileSizeNumber longValue];
	NSLog(@"File: %@, Size: %ld", pathImage, fileSize);
    if(fileSize<=0){
        NSLog(@"Error: file size incorrect!");
        //richiamo l'errorUpload sul Delegate in caso di success
        if (self.delegate && [self.delegate respondsToSelector:@selector(unsuccessUpload)]) {
            [self.delegate unsuccessUpload];
        }
        return;
    }

    //se la foto è troppo grande, la comprimo
    UIImage *originalImage = [[UIImage alloc]initWithContentsOfFile:pathImage];

    //NSData *dataImage = [NSData dataWithContentsOfURL:[NSURL URLWithString:pathImage]];
    //NSData *dataImage = [[NSFileManager defaultManager] contentsAtPath:pathImage];

    CGFloat compression = 0.9f;
    CGFloat maxCompression = 0.1f;
    int maxFileSize = MAXFILESIZE_IMAGE_UPLOAD;

    //comprimo l'immagine e la salvo in JPEG, se è troppo grande
    NSData *dataImage = UIImageJPEGRepresentation(originalImage, compression);

    while ([dataImage length] > maxFileSize && compression > maxCompression)
    {
        compression -= 0.1;
        dataImage = UIImageJPEGRepresentation(originalImage, compression);
    }

    NSMutableURLRequest *postRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:serviceURL]];

    [postRequest setHTTPMethod:@"POST"];

    NSString *boundary = @"BVillage";
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
    [postRequest addValue:contentType forHTTPHeaderField: @"Content-Type"];

    NSMutableData *body = [NSMutableData data];

    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"filename\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[filename dataUsingEncoding:NSUTF8StringEncoding]];

    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"Content-Disposition: form-data; name=\"userfile\"; filename=\"tmpFile.jpg\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[NSData dataWithData:dataImage]];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    [postRequest setHTTPMethod:@"POST"];
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    // Setting a timeout
    postRequest.timeoutInterval = 60.0;
    [postRequest setHTTPBody:body];

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

    /*[NSURLConnection sendAsynchronousRequest:postRequest
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
     */
    [URLConnection asyncConnectionWithRequest:postRequest completionBlock:^(NSData *data, NSURLResponse *response) {

        NSLog(@"Succeeded! Received %d bytes of data",[receivedData length]);
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

        NSDictionary *responseJSON = [NSJSONSerialization
                                      JSONObjectWithData:data
                                      options:kNilOptions error:nil];

        NSLog(@"Response JSON: %@",responseJSON);

        //if(!error){
            //richiamo il successUpload sul Delegate in caso di success
            if (self.delegate && [self.delegate respondsToSelector:@selector(successUpload)]) {
                [self.delegate successUpload];
            }
            return;
        /*}
        else{
            //richiamo l'errorUpload sul Delegate in caso di success
            if (self.delegate && [self.delegate respondsToSelector:@selector(unsuccessUpload)]) {
                [self.delegate unsuccessUpload];
            }
            return;
        }*/

    } errorBlock:^(NSError *error) {
        ////richiamo l'errorUpload sul Delegate in caso di success
        if (self.delegate && [self.delegate respondsToSelector:@selector(unsuccessUpload)]) {
            [self.delegate unsuccessUpload];
        }
        return;
    } uploadProgressBlock:^(float progress) {
        if (self.delegate && [self.delegate respondsToSelector:@selector(updateProgressBar:)]) {
            [self.delegate updateProgressBar:progress];
        }

    } downloadProgressBlock:^(float progress) {
        //
    }

    ];

}

@end

Come potete vedere, ho utilizzato la libreria URLConnection, per poter mostrare durante il caricamento del file una “progress bar” (come spiegato in questo post: http://messagesenttodeallocatedinstance.wordpress.com/2012/04/10/nsurlconnection-with-blocks/).

Per poter usare la classe UploaderDelegate e procedere all’upload della foto, basta inserire nel vostro codice la seguente chiamata:

//chiamata al wrapper per l'upload dei file sul server
UploaderDelegate *uploaderDelegate = [UploaderDelegate sharedInstance];
uploaderDelegate.delegate = self;

NSString *pathFile = ABSOLUTE_PATH_OF_YOUR_PHOTO;
NSString *photoName = FILENAME_OF_YOUR_PHOTO;

    [uploaderDelegate sendImageToServerWithURLPath:pathFile withFilename:photoName toServiceURL:UPLOAD_IMAGE_URL];

NOTA. E’ importante settare che il pathFile sia il percorso assoluto alla vostra foto (comprensivo di nome del file e di estensione). La variabile photoName è il nome della foto (senza estensione) così come verrà salvata sul vostro server. Al posto dell’etichetta UPLOAD_IMAGE_URL ricordatevi di sostituire la URL del vostro servizio PHP di upload (per esempio, http://www.francescoficetola/upload/image_upload.php)

Ricordatevi di importare la classe suddetta e di settare la “delega” nel vostro ViewController, inserendo l’UploaderProtocol. Come ad esempio:

//
//  MyViewController
//
//  Created by Fr@nk on 07/01/14.
//  Copyright (c) 2014. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "UploaderDelegate.h"
#import "KKProgressToolbar.h"

@interface MyViewController : UIViewController<UploaderProtocol, KKProgressToolbarDelegate>{

    IBOutlet UIImageView *imageView;
    IBOutlet UIButton *imageUploadButton;
    KKProgressToolbar *progressBar;
}

/* metodi di delegate */
-(void)successUpload;
-(void)unsuccessUpload;
-(void)updateProgressBar:(float)progress;
-(IBAction)startProgressBarLoading;
-(IBAction)stopProgressBarLoading;

-(IBAction)sendPhotoToServer:(id)sender;

@property (nonatomic, strong) IBOutlet UIImageView *imageView;
@property (nonatomic, strong) KKProgressToolbar *progressBar;
@property (nonatomic, strong) IBOutlet UIButton *imageUploadButton;

@end

Per poter gestire gli eventi relativi all’upload, occorre definire nel vostro ViewController i seguenti metodi di delegate:

  • successUpload: richiamato dall’UploaderDelegate in caso di upload con successo
  • unsuccessUpload: richiamato dall’UploadDelegate in caso di errore nell’upload
  • updateProgressBar: richiamato dall’UploadDelegate durante l’upload per aggiornare la percentuale di caricamento sulla progress bar
  • startProgressBarLoading: da richiamare, lato app, per inizializzare la progress bar
  • stopProgressBarLoading: da richiamare, lato app, per stoppare la progress bar

NOTA. Per gestire la progress bar ho utilizzato la seguente libreria: KKProgressToolbar

#pragma mark Uploader methods

-(void)updateProgressBar:(float)progress{
    self.progressBar.progressBar.progress = progress;
}

-(void)successUpload{
    NSLog(@"successUpload");
    //in caso di successo aggiorno rimuovo la progress bar
    [self stopProgressBarLoading];

}

-(void)unsuccessUpload{

    NSLog(@"unsuccessUpload");
}

#pragma StatusBarLoading

-(void)addProgressBar{

    //aggiungo la progress view:
    CGRect progressBarFrame = CGRectMake(0, self.view.frame.size.height-100, self.view.frame.size.width, 44);
	self.progressBar = [[KKProgressToolbar alloc] initWithFrame:progressBarFrame];
	self.progressBar.actionDelegate = self;
    self.progressBar.progressBar.progress = 0;
    self.progressBar.statusLabel.text = @"Loading from server...";
	[self.view addSubview:self.progressBar];

    [self startProgressBarLoading];

}

- (void)didCancelProgressBarButtonPressed:(KKProgressToolbar *)toolbar {
    [self stopProgressBarLoading];
    //TODO: eliminare la richiesta di upload...
}

- (IBAction)startProgressBarLoading  {

    [self.progressBar show:YES completion:^(BOOL finished) {
        //Code
    }];

}

- (IBAction)stopProgressBarLoading {
    [self.progressBar hide:YES completion:^(BOOL finished) {
        //code
    }];

}

Creative Commons License
This work by Francesco Ficetola is licensed under a Creative Commons Attribution 4.0 International License.
Based on a work at www.francescoficetola.it.
Permissions beyond the scope of this license may be available at http://www.francescoficetola.it/2014/01/06/ios-upload-di-immagini-da-app-su-server/.

[iOs] Idee e codici per menù ed altri componenti grafiche con effetti e transizioni su Code4App

Condivido qui un sito interessante, Code4App, dove vengono proposti menù ad effetto con transizioni:

In realtà, sul sito di Code4App troverete anche tante altre idee per la vostra app, come tab bar, animazioni, calendar, tabelle, ecc. ecc. Ovviamente troverete anche i codici sorgenti da scaricare e provare in xCode.

Ecco le categorie attualmente disponibili:

CodeApp - Category

Devo dire che è davvero una bella idea quella di raccogliere su un sito tutti i progettini utili ed interessanti condivisi da utenti di GitHub, BitBucket ed altri. Spesso, infatti, è difficile cercare quello che serve sui social network per programmatori, perché non mettono a disposizione una “vetrina” immediata che consente di individuare il componente desiderato.

Ecco i menù che ho trovato interessanti su Code4App e che ho usato per una mia app:

ios_menu popupscroll_menu ios

Il Freemium: Le app economiche potrebbero uccidere l’App Store

Condivido la posizione di Lex Friedman (grande contributor su MacWorld) sulle app economiche pubblicate sui mobile store (non solo di Apple). Eccovi la traduzione e ringrazio il mio amico Marco per avermela segnalata:

freemium-vs-premium

Le applicazioni economiche potrebbero uccidere l’App Store (di Lex Friedman)

Più si abbassano i prezzi per il software dell’iPhone, più la situazione per noi consumatori potrebbe peggiorare. Lo smartphone è probabilmente una delle cose più costose che abbiamo in tasca quotidianamente. Eppure molte persone sono decisamente avare quando guardano gli scaffali virtuali dell’App Store. Come mai? Ironicamente le cose che sono economiche nel breve periodo tendono a diventare costose a lungo andare.

Non sorprende che le applicazioni gratuite siano decisamente più popolari delle applicazioni a pagamento: piace a tutti avere qualcosa senza spendere un centesimo. Ma la cosa strana è che la gente consideri un’applicazione da tre euro decisamente costosa, ed una da dieci euro dal prezzo addirittura esorbitante. Conosco gente che gioca allo stesso gioco gratuito ogni singolo giorno, sorbendosi tutti i banner pubblicitari, piuttosto che spendere cinque euro una volta sola ed andare avanti per sempre senza alcun banner pubblicitario.
Nel momento in cui scrivo, tra le prime venti applicazioni più vendute dell’App Store 15 costano un euro e la più costosa viene sette euro. Il prezzo medio delle top 100 app a pagamento è inferiore ai due euro.
Mi colpisce che così tanti possessori di dispositivi iOS non capiscano che non stanno agendo nel loro interesse né a breve né a lungo termine quando sorridono al pensiero di spendere soldi sull’App Store. I clienti che spendono un sacco di soldi per l’hardware di dispositivi iOS si puniscono poi risparmiando sulle app.

Ottieni ciò per cui paghi.

Le applicazioni a pagamento tendono ad essere migliori delle alternative gratuite. Sono in pochi gli utenti Twitter che pensano che l’applicazione ufficiale offra la miglior esperienza utente, ma molti rimangono su questa semplicemente per evitare di confron- tarsi con le alternative a pagamento come Tweetbot oppure Twitterrific.

Molte applicazioni gratuite sono buone. Ma quando paghi per un’applicazione premium, spesso paghi per una esperienza utente più profonda, una per la quale tu sei il cliente più importante e non sono gli inserzionisti i responsabili del supporto dietro le quinte alla app “gratuita”.

La ragione per cui gli sviluppatori fanno pagare per le proprie applicazioni è che sviluppare un’applicazione ha un costo. Con quello che lo sviluppatore guadagna dalla vendita della sua applicazione può rientrare nell’investimento iniziale di tempo e risorse ed investire nello sviluppo futuro dell’applicazione. I clienti beneficiano di questo ottenendo applicazioni migliorate o nuove applicazioni da questi sviluppatori, invece di applicazioni gratuite abbandonate e di qualità inferiore.

Per un’applicazione da un euro uno sviluppatore guadagna circa 70 centesimi. Di questo passo uno sviluppatore deve vendere più di 70 mila copie per guadagnare almeno 50 mila euro. Per uno sviluppatore indipendente questi servono a coprire le spese, il costo di sviluppo e di progettazione, e poi vivere di quello che resta. Ma se l’applicazione da un euro viene sviluppata da una piccola società di tre persone, è necessario venderne almeno 300 mila affinché il business sia sostenibile. Ovviamente se gli sviluppatori mettono in vendita la loro app per un euro non dobbiamo sentirci in colpa acquistandole. Ma gli sviluppatori mettono in vendita le loro applicazioni a costi così bassi perché sanno che è il prezzo massimo per cui i clienti pagherebbero. E se questo è vero le applicazioni a basso prezzo stanno avendo un impatto negativo su parecchie aziende reali e potenziali.

L’ascesa del Freemium

Gli sviluppatori, comunque, sono ricchi di risorse. Così, visto che molti utenti detestano dover pagare per le applicazioni, abbiamo visto l’ascesa del modello Freemium: puoi scaricare l’app o il gioco gratuitamente, ma per poter continuare a giocarci dovrai fare uno o più acquisti in-app. E questi micropagamenti non sono solamente fastidiosi, ma a lungo andare possono costare all’utente molto di più. Ad esempio: EA Real Racing 2 inizialmente costava poco meno di sette euro. Poi è uscito con il modello Freemium, che costa agli utenti decisamente di più sul lungo periodo, semplicemente per ottenere lo stesso diverti- mento che anche Real Racing 2 offriva.

Fino a quando i clienti dell’App Store non mostreranno volontà a spendere soldi per ottime applicazioni, gli sviluppatori dovranno continuare su questa strada semplicemente per rimanere a galla.

Non è poi così caro.

Un iPhone 5 senza contratto costa di listino 729 euro e se si sceglie un iPhone con contratto di due anni alla fine si arriva a pagare almeno la stessa cifra. A confronto, un’app di quelle “care” può arrivare a costare circa l’uno per cento del prezzo dell’iPhone. E lo vale.

Non si compra un Kindle solamente per leggere il dizionario ed il manuale di istruzioni precaricato. E così non si dovrebbe comprare un iPhone solamente per utilizzare le applicazioni gratuite. Equivale a mentire a se stessi, solamente perché ognuno è ormai condizionato pensando che spendere cinque euro per un app sia troppo. Non è sbagliato pagare per prodotti di qualità.

Spendere soldi per buone applicazioni significa anche investire in ottime applicazioni che verranno create in futuro. Sistemiamo l’economia dell’App Store e iniziamo a pagare per le applicazioni senza rabbrividire quando ne vediamo una per quattro euro.

Tanti possessori di dispositivi iOS non capiscono che non stanno agendo nel loro interesse né a breve né a lungo termine quando sorridono al pensiero di spendere soldi sull’App Store.

 

Un altro articolo interessante (più vecchiotto) sull’argomento: App Store: con i prezzi troppo bassi è la fine?

 

Ecco quello che penso:

Sono in parte d’accordo con l’articolo di Friedman, perché sono ancora piuttosto scettico sulla politica del business via app. La concorrenza è spietata ed è difficile essere all’altezza nello sviluppare un’app in grado di vendere tanto sullo store.
Secondo me, ci si guadagna quando c’è un progetto di marketing vincente e strutturato dietro. La politica del guadagno tramite advising stanca l’utente, ma può risultare vincente nel breve periodo. Il freemium è davvero una bella trovata e un’ancora di salvezza (Vedi: Freemium VS. Premium)
Nel piccolo si può guadagnare vendendo l’idea e l’app a clienti o investitori. Purtroppo, l’app business non fa girare molti soldi in Italia, perché i clienti non hanno la concezione dello sforzo che si fa nel realizzarle e non comprendono ancora le potenzialità e l’utilità che possono offrire agli utenti finali. In Italia facciamo ancora ben poco tramite mobile (vedi anche i pagamenti online o la disponibilità di servizi a distanza utili al cittadino…).

Guardate un po’ i guadagni che si traggono dal modello Freemium:
freemium-percent

[iOs] Link Maker: generazione dinamica dei link di Apple Store

Per la generazione dei link di tutti gli articoli (ebook, musica, app, podcast, audiolibri, ecc.) disponibili su iTunes, iBook ed App Store, Apple mette a disposizione la pagina di iTunes Link Maker:  http://linkmaker.itunes.apple.com

Link Maker Apple

Esistono, in realtà, vari strumenti utili per la generazione dei link (creare link ad iTunes), utili però solo per la creazione di widget e link statici. Ad esempio, in questo Q&A si spiega come generare link a propri item (come, ad esempio, alla pagina delle app sviluppate da uno sviluppatore o da una società: Creating easy-to-read short links to the App Store for your apps and company).

Tuttavia, non esiste un vero e proprio framework che consenta di recuperare dinamicamente tali link. Occorre richiamare una URL di servizio, fornita proprio da Apple, così come si legge dalla Search API Documentation.

Ho così realizzato uno “scriptino” PHP in grado di restituirvi i risultati della pagina di iTunes Link Maker in formato JSON. Per fare ciò, mi sono aiutato con uno sniffer e ho recuperato tutte le URL richiamate dopo aver lanciato una ricerca sulla pagina di Link Maker. Le URL generate “dietro le quinte” dalla ricerca sono un bel po’ e cambiano in base alla combinazione tra “media” selezionato (categoria di item: audio, video, app, ebook, ecc.) e relative entity (sottocategorie di item non selezionabili, ma impostate da Apple come ulteriori keyword di ricerca, in base al media selezionato).

Potete provare la ricerca dalla form di esempio disponibile qui:

Nello script PHP che ho realizzato, non faccio altro che richiamare la stessa URL di Apple, passando una combinazioni di parametri (essenzialmente cambiano “media” ed “entity“):

http://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/wsSearch?term=%s&country=%s&media=%s&entity=%s&limit=%s&genreId=%s&version=2&output=json

Al posto di %s occorre inserire dei valori ammissibili (la lista completa la trovate sulla documentazione ufficiale – Search API Documentation):

  • term: contiene la keyword di ricerca (ad esempio, “Oasis what’s the story morning glory”)
  • country: identificativo del Paese (IT, US, UK, ecc.). La ricerca restituirà gli item disponibili sugli Apple Store del paese selezionato. La lista completa dei Paesi è disponibile qui: http://www.francescoficetola.it/link-maker/countries.json
  • media: deve contenere la categoria di item. I valori ammissibili sono: audiobook (per gli AudioLibri), shortFilm (per i Cortometraggi), movie (per i Film), software (per le iOs app), ebook (per i Libri), macSoftware (per le Mac Apps), music (per i brani audio), podcast (per i PodCast), musicVideo (per i Video).
  • limit: numero massimo di risultati di ricerca da restituire;
  • entity: contiene le sottocategorie dei prodotti. Questo valore dipende dal parametro media impostato (le varie combinazioni sono elencate di seguito);
  • genreId: (opzionale) contiene il codice relativo al genere di media desiderato. Esistono varie combinazioni, disponibili al seguente link:

Ecco le combinazioni di media e relative entity, così come mappate nel mio script PHP:

//AUDIOLIBRI
if($media=='audiobook'){
   $entity = array('audiobookAuthor','audiobook');
}

//CORTOMETRAGGI
if($media=='shortFilm'){
   $entity = array('shortFilmArtist','shortFilm');
}

//FILM
if($media=='movie'){
   $entity = array('movieArtist','movie');
}

//iOS Apps
if($media=='software'){
   $entity = array('softwareDeveloper','software','iPadSoftware');
}

//LIBRI
if($media=='ebook'){
   $entity = array('ebookAuthor','metaEbook,textbook,ebook');
}

//Mac Apps
if($media=='macSoftware'){
   $entity = array('softwareDeveloper','macSoftware');
}

//MUSICA
if($media=='music'){
   $entity = array('musicArtist','song','album','musicVideo');
}

//PODCAST
if($media=='podcast'){
   $entity = array('musicArtist','podcastAuthor','podcast');
}

//VIDEO
if($media=='musicVideo'){
   $entity = array('musicVideoArtist','musicVideo');
}

Se volete richiamare direttamente il mio script PHP, senza passare dalla form di esempio su linkata (magari per farvi restituire un JSON da utilizzare nelle vostre app), eccovi la URL diretta:

  • http://francescoficetola.it/link-maker/linkmaker.php?term=%s&country=%s&media=%s&limit=%s&genreId=%s

I valori ammissibili da passare sono quelli espressi precedentemente e di seguito riassunti:

  • media: audiobook, shortFilm, movie, software, ebook, macSoftware, music, podcast, musicVideo
  • country: IT, US, UK, ecc.
  • term: la vostra query di ricerca (ad esempio, Oasis what’s the story morning glory”)
  • limit: (opzionale, di default è impostato a 50) determina il numero massimo di risultati che occorre restituire per ognuna delle combinazioni di URL di ricerca richiamate da Apple, in base al media impostato.
  • genreId: (opzionale) codice del genere degli item, il cui valore ammissibile è disponibile nel dizionario lmMediaTypeAndGenreDictionaries fornito da Apple.

Le combinazioni di entity sono definite direttamente nello script e non occorre specificare il parametro in input.

Ecco un esempio di ricerca:

http://francescoficetola.it/link-maker/linkmaker.php?term=jovanotti+bella&country=IT&media=music&limit=50&genreId=14

[iOs] Aggiornamento ad xCode 5: novità e how-to ai problemi post-upgrade

xCode 5Dopo gli upgrade di xCode, si hanno gli ormai inevitabili problemi di compatibilità o di change configuration di progetti scritti con una versione precedente. Sono passato al nuovo xCode 5 da quando è stato rilasciato per gli sviluppatori iOs, imbattendomi in alcune problematiche, e ho pensato di scrivere una sorta di “how-to” per la loro risoluzione, riportandolo in fondo a questo articolo.

Novità di xCode 5. Vediamo prima quali sono le novità introdotte in xCode 5:

  • Configurazione automatica: i progetti vengono automaticamente configurati per supportare i servizi Apple come iCloud, Passbook Game Center. Inserendo il proprio Apple ID, è possibile gestire anche il proprio team, i certificati e gli entitlements, il tutto direttamente da IDE (cosa che prima si effettuava connettendosi al Provisioning Portal). In base ai servizi richiesti, xCode importa anche i framework necessari e crea gli appropriati provisioning profiles, “firmando” l’app ogni volta che viene “buildata”.
  • Test Navigator: il test-driven development diventa più semplice, utilizzando il nuovo Test Navigator, editor in cui creare, modificare e lanciare gli unit tests. Si possono lanciare singoli test o gruppi di test, grazie ad Assistant Editor.
  • Bots per il Continuous Integration: xCode si integra (integrerà) con l’OS X Server del Sistema Operativo OS X Mavericks, permettendo la creazione di “bots” che “buildano” continuamente l’app ed eseguono i test e lo static analyzer per scovare potenziali bug. I bots possono essere lanciati su qualsiasi Mac presente in rete, monitorando l’integration work su macchina locale.
  • Auto Layout: l’auto-layouting permette di “aggiustare” automaticamente la dimensione delle view grafiche, il loro orientamento e la localizzazione (internazionalizzazione), direttamente da Interface Builder. Introdotti a tale scopo il free-form canvas e i constraints (in realtà già presenti nelle versioni precedenti di xCode).
  • Asset Management: grazie agli Asset Catalogs (salvati su file compressi con estensione .xcassets) si possono gestire le immagini inserite nelle app. Le diverse versioni della stessa immagine (per le differenti risoluzioni dei device) vengono collezionate tutte in un singolo file. L’Asset Catalog sceglie quale immagine renderizzare in base al device su cui si testa e permette anche di scalarla dinamicamente.
  • Debug deeper analysis: con il nuovo strumento di debug è possibile misurare anche il consumo dei dati, la memoria CPU occupata, l’energia in uso, e altri valori prestazionali (deeper analysis), allertando lo sviluppatore in caso di overhead.
  • Visual Debugger: il debugger utilizzato è l’LLDB engine (nelle precedenti versioni c’era anche GDB, adesso completamente rimosso). Resa più leggibile e chiara la visualizzazione dei messaggi di debug ed inseriti “data tips” più esplicativi. Finalmente, si può “ispezionare” con un singolo click la variabile/oggetto e stampare le sue proprietà direttamente sulla debug console.
  • Source Control: migliorato il sistema di versioning che visualizza anche i branch attivi di progetto e permette agevolmente di switchare, creare e mergiare i branch stessi. E’ possibile gestire in un singolo punto tutte le repository (Accounts preferences) e l’OS X Server su OS X Mavericks permette (permetterà) di “hostare” anche repository GIT per il team di sviluppo.

 

Problemi post-upgrade ad xCode 5. Riporto di seguito le anomalie riscontrate (e corrette) dopo l’aggiornamento ad xCode 5, su progetti scritti su versioni precedenti.

Nota. Questo articolo sarà costantemente aggiornato, man mano che mi si presenteranno anomalie su “vecchi” progetti nel nuovo ambiente di xCode 5.

  • Impossibile debuggare, visualizzazione del messaggio “Attaching appname” con schermata nera sul vostro Simulatore iOs. Se non riuscite più a debuggare le vostre app, vi viene mostrato continuamente il messaggio “Attaching <appname>” e lo screen del Simulatore vi rimane nero, senza dar minimo segno di visualizzazione della vostra app, nelle precedenti versioni di xCode bastava switchare dal debugger LLDB a GDB (Scheda Product>>Edit Scheme). Adesso, avendo eliminato il debugger GDB, tale procedura non funziona più e vi conviene seguire il seguente “how-to”: http://stackoverflow.com/questions/15174282/why-does-the-lldb-debugger-constantly-fail-to-attach. Occorre cioè assicurarsi che sul vostro file di hosts (presente al patch /private/etc/hosts del vostro Mac) si faccia lookup” di localhost su 127.0.0.1. Nel mio file di hosts, invece, vi erano mappati altri valori (colpa di Adobe Professional!).

(continua…)

 

[iOs] Librerie per la scansione di codici a barre ed il riconoscimento OCR

Come acquisire un codice a barre in un’app iOs? Ce lo dice Marco Giraudo, giovane sviluppatore iOs e PHP, che mi ha mandato questo ottimo articolo, in cui si è trovato a valutare delle librerie per la scansione di codici a barre (BarCode Reader), ma anche per il riconoscimento OCR.

iPhone_barcode_scanner

Eccovi l’esperienza di Marco, a cui va il mio ringraziamento:

“Mi sono fatto questa domanda nelle ultime settimane per motivi di lavoro e vi voglio riportare 2 esempi che sono riuscito a trovare e testare. In particolare, mi serviva riconoscere un codice a barre e cosi ho utilizzato due librerie: ZBarSDK e Tesseract .

1° Esempio: ZBarSDK

ZBarSDKhttp://zbar.sourceforge.net/iphone/sdkdoc/

C’è stato subito un problema da superare, dopo l’installazione sul mio progetto xCode:

Warning: Only the iPhone 3GS and iPhone 4 are supported, as they have a camera with auto-focus. The ZBar library does not support the iPhone 3G and is unlikely to ever support it.

Su iPhone 5 con iOs 6 e successivi mi dava problemi, ma ho trovato la soluzione su http://stackoverflow.com:

http://stackoverflow.com/questions/12506671/zbar-sdk-is-not-working-in-ios6

Oltre a settare come “Valid Architecture” il processore armv7s nelle impostazioni del vostro progetto xCode, potete provare a scaricare ed installare la versione beta compatibile con iOs 6 (ZBarSDK-1.3.1.dmg):

http://sourceforge.net/projects/zbar/files/iPhoneSDK/beta/

Una  volta installato il .DMG, l’unica cosa da fare è leggere il file README riportato e seguire le istruzioni per inserire la libreria nel proprio progetto:

    • trascinare la cartella ZBarSDK nel proprio progetto
    • inserire nel proprio progetto i Frameworks: AVFoundation (weak), CoreMedia (weak), CoreVideo (weak), QuartzCore, libiconv.dylib

Per usare ZBar, basta importare nel vostro controller la libreria:

#import “ZBarSDK.h”

Nello stesso .dmg troverete una cartella con molti esempi da cui prendere spunto. L’ho anche provata con iPhone5 con su installato ios7 beta4 e funziona benissimo.

2° Esempio: Tesseract-OCR (Google)

Secondo esempio che vi riporto è tesseract-ocr, un OCR Engine che vi permette di riconoscere i testi riportati in un’immagine. Ecco il sito ufficiale su Google Code:

http://code.google.com/p/tesseract-ocr/

Per far funzionare l’OCR Engine in iOs, esiste un Wrapper: Tesseract for iOs (https://github.com/ldiqual/tesseract-ios)

Eccovi le istruzioni di installazione:

http://lois.di-qual.net/blog/install-and-use-tesseract-on-ios-with-tesseract-ios/

Spero che questi due esempi possano esservi utili. Alla prossima!”

[iOs] Quick Objective-C Tutorial

Consiglio un bel tutorial per chi volesse iniziare la programmazione su Objective-C:

This tutorial is the place to learn the Objective-C programming language. It’s designed to serve as both a concise quick-reference and a comprehensive introduction for newcomers to the language. A familiarity with basic programming concepts like variables, functions, and objects is recommended, but not strictly required.

Published  – Tested on Xcode 4.5 with Apple LLVM compiler 4.1ry's tutorial

Molto fighe sono le immagini esemplificative e la semplicità di scrittura. Grande Ry!

Creative Commons License
This work by Francesco Ficetola is licensed under a Creative Commons Attribution 4.0 International License.
Based on a work at www.francescoficetola.it.
Permissions beyond the scope of this license may be available at http://www.francescoficetola.it/2013/07/31/ios-quick-objective-c-tutorial/.