Swift 3 e la Configurazione Remota

Oggi parleremo di Configurazione Remota o anche Remote Configuration, ma cosa è?

Prendiamo come esempio l’applicazione Costituzione Italiana. Questo genere di progetto ha al suo interno alcune tecnologie basilari come Google Analytics, Arena Daemon e altri servizi esterni.
Cosa accade se ad un certo punto volessi disattivarne uno? Esatto, dovrei fare una nuova build e inviarla ad Apple.

Se volessi fare dei test A/B sarebbe un vero dramma.

La soluzione è avere una configurazione remota. L’app quindi prima di avviare i servizi controlla un file di configurazione remoto ed applica i comportamenti indicati.

Sul mio server ho inserito un piccolo file JSON:

{
	"enableGoogleAds": true,
	"enableGoogleAnalytics": true
}

L’app quindi si comporterà in base a questi due valori.

A questo punto non ci rimane che scrivere il codice Swift e per l’occasione ne approfitteremo per iniziare a scrivere qualcosa nella sua ultima versione, la 3.

Creiamo quindi una classe chiamata RemoteConfiguration.
Dovrà utilizzare il pattern Singleton così da avere una singola istanza per tutta la vita della nostra app.

class RemoteConfiguration {
	static let sharedInstance = RemoteConfiguration()
}

Aggiungiamo poi una proprietà chiamata baseURL:URL che andremo a configurare in un secondo momento. Poi ci serve un metodo che ci permette di recuperare il file. Questo è il momento giusto per utilizzare una callback, quindi creiamo un metodo chiamato configuration e come argomento deve accettare una closure di questo tipo: (dictionary:[String:AnyObject]))->().

class RemoteConfiguration {
	static let sharedInstance = RemoteConfiguration()
	var baseURL:URL?

	func configuration(handler:@escaping (_ dictionary:[String:AnyObject]?)->()) {

	}
}

La logica che ho pensato è questa: Se i dati non sono mai stati scaricati vado a recuperarli dall’URL indicato,  se invece li ho già scaricati non farò alcuna chiamata al server ed utilizzerò i dati in memoria.
Per farlo serve una proprietà privata configurationDictionary in cui salveremo i dati.

class RemoteConfiguration {
	static let sharedInstance = RemoteConfiguration()
	var baseURL:URL?

	private var configurationDictionary:[String:AnyObject]?

	func configuration(handler:@escaping (_ dictionary:[String:AnyObject]?)->()) {

	}
}

Adesso andiamo a creare la magia.
Per convenienza ho scritto una piccola classe chiamata Request che si occupa di scaricare i dati dalla rete in modo asyncrono, la troverete nel file Playground.

Request ritorna un oggetto Data che andremo a convertire in un dizionario usando la classe JSONSerialization e il metodo jsonObject.
Questo metodo solleva un’eccezione ma in questo momento non ci interessa controllare l’eventuale errore e quindi  possiamo utilizzare try? in modo da avere un oggetto Optional. In alternativa avremmo dovuto utilizzare un blocco do {} catch {}.

class RemoteConfiguration {
	static let sharedInstance = RemoteConfiguration()
	var baseURL:URL?
	
	private var configurationDictionary:[String:AnyObject]?
	
	func configuration(handler:@escaping (_ dictionary:[String:AnyObject]?)->())
	{
		guard let baseURL = baseURL else { assertionFailure("URL cannot be nil"); return }
		
		if let configuration = configurationDictionary
		{
			handler(configuration)
		}
		else
		{
			Request.url(url: baseURL, completion: {
				data, error in
				
				if let data = data, error == nil
				{
					if let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String:AnyObject]
					{
						handler(json)
						return
					}
				}
				
				handler(nil)
				
			})
		}
	}
}

È arrivato il momento di provare il nostro codice, configuriamo RemoteConfiguration e richiediamo i dati:

let rc = RemoteConfiguration.sharedInstance
rc.baseURL = URL(string: "http://localhost/pills/p-01/remote-config.json")
rc.configuration { configuration in
	if let configuration = configuration
	{
		debugPrint(configuration)
	}
}

Se tutto è andato bene dovremmo vedere nel debugger la stampa del dizionario:

["enableGoogleAds": 1, "enableGoogleAnalytics": 1]

Questa classe è un ottimo punto di partenza nella nostra implementazione di una configurazione remota. Personalmente la trovo davvero molto utile per fare test A/B e per attivare o disattivare funzionalità o servizi senza dover ricompilare tutto.

Ovviamente è un punto di partenza, ci sono molte ottimizzazioni da poter fare e funzionalità da implementare. Potrebbero essere argomento nei prossimi articoli.

Potete scaricare il file Playground da GitHub.

Happy coding!

Costituzione Italiana 3.0

Era molto tempo che non aggiornavo Costituzione Italiana. Ho voluto approfittare del cambio di linguaggio di programmazione (Swift) da parte di Apple per realizzare un’applicazione totalmente nuova.

Costituzione Italiana 3.0 quindi si aggiorna completamente. Ho riscritto ogni cosa, compreso il testo della Costituzione.
Adesso il motore è più snello e semplice da aggiornare, questo significa che in futuro potrete avere migliorie in modo più veloce.

Purtroppo abbiamo perso la compatibilità con la vecchia versione, ciò significa che i favoriti e le note non sono più compatibili.

Spero apprezziate il mio lavoro. Correte ad aggiornarla!

Prima demo di Save the Astronaut

Questo è il mio primo “vero” videogioco. Ne ho già fatti altri in realtà, Slidespace e HolyTrivia, ma questo è molto più strutturato e più complesso.

Poi è realizzato con cocos2d e questo mi ha permesso di concentrarmi sul gioco vero e proprio.

Di lavoro ce né ancora tantissimo, ma già mi reputo soddisfatto ad essere riuscito a fare tutto questo.
Per la precisione devo realizzare tutti i livelli (e inventarmi un po’ di dinamiche differenti), creare le animazioni di morte, vincita e quanto altro, aggiungere suoni e musica e aggiungere la leaderboard. Insomma, tanto da fare.

Godetevi il video e ditemi cosa ne pensate.

Presto nuovi aggiornamenti.

Sviluppare un’applicazione per iOS

Sono passati poco più di 6 anni da quando Apple ha rilasciato il primo l’SDK e da allora le cose sono cambiate molto.

Sviluppare un’applicazione per iOS oggi infatti non è come nel 2008. In questi anni si sono aggiunti nuovi dispositivi con differenze hardware sostanziali, il sistema operativo ha fatto grandissimi cambiamenti, anche a livello grafico e di user experience. Per non parlare di tutti i problemi di sicurezza nati e per i quali sono state creati appositi comportamenti.

Insomma, le cose sono cambiate drasticamente.

Apple sta facendo di tutti per aiutarci. Con il tool di sviluppo XCode e con tutte le API che introduce puntualmente ad ogni release.

Nonostante tutto lo sviluppo si è complicato, ci sono maggiori dettagli da non sottovalutare assolutamente.

  • La richiesta delle autorizzazioni per:
    • Location
    • Motion
    • Calendario
    • Promemoria
    • Notifications (push e local)
    • Foto
    • Contatti
    • Bluetooth
    • Microfono
    • HealthKit
    • HomeKit
  • L’uso dei social interni come:
    • Facebook
    • Twitter
    • Flickr
    • Vimeo
  • La scelta se utilizzare il framework di iOS per Facebook o l’SDK di Facebook stesso.
  • L’utilizzo di SchemeURL.
  • L’uso di Launch images adeguate per supportare tutti i device.
  • L’uso di Size Classes per supportare i device con schermi differenti.
  • L’implementazione di Welcome views per la spiegazione e l’attivazione dei servizi da autorizzare.

Questi sono solo alcuni dei punti da dover tenere di conto. Poi ci sono tutte quelle sfumature legate alle UI/UX (User Interface/User Experience) come l’utilizzo di interfacce proprietarie.

Dopo di che c’è da tenere conto del nuovo sistema di transizione (TransitionCoordinator) delle view. E’ vero che adesso possiamo personalizzare ogni genere di animazione ma è altrettanto vero che questo tipo di ingegnerizzazione tende a complicare e rendere difficile lo sviluppo e la futura manutenzione.

Poi c’è la parte di test e debug. Il simulatore di iOS è uno strumento davvero completo, ma alcune funzionalità necessitano di test sul device. Ad esempio tutto ciò che riguarda la fotocamera, il GPS e il Motion non sono pienamente o per niente (dipende dai casi) supportati dal simulatore e quindi è necessario avere vari dispositivi per testare l’app.

Ma non solo, infatti può capitare di avere un comportamento sul simulatore e ritrovarsi con un comportamento differente sul device, per questo è necessario avere sempre a portata di mano qualche device di test.

Di cose da tenere in considerazione ce ne sono davvero molte, questo è solo l’1%.

Quindi posso affermare che oggi è molto più complesso e richiede molto più tempo sviluppare un’app per iOS che nel 2008.
La forza sta sicuramente nell’avere tanta esperienza così da riuscire a valutare velocemente tutti i problemi. Ed ovviamente una base di codice riutilizzabile :)

Buon lavoro a tutti!

CocosViewController – How to use Storyboards and Cocos2d V3+

I will write this tutorial in English, so, sorry for the language errors ;)

Some weeks ago I wrote a simple class for Cocos2D v3+ to use Cocos2D and Storyboards called CocosViewController.

CocosViewController is a UIViewController subclass that create CCDirector and put it in the controller view.

So, with this class we can have a Cocos2D view controller inside a Storyboard environment but we can also add UIKit elements above the Cocos2D view.

So, start this little tutorial.

How to use CocosViewController.

Create a new project (or use an existing one, but I recommend you to start with a new one to become familiar with the class) with SpriteBuilder, you can use the latest 1.2 version with Cocos2D v3.2.

cvc_1

Remove AppDelegate class and replace with the one in the CocosViewController project. Then copy CocosViewController.h/mm files in your project directory and add it in the xcode project.


cvc_2

cvc_3

Now locate the file named main.mm and rename the @”AppController” string with @”AppDelegate”.
Note: you can also rename the AppDelegate class, but for this tutorial this is the fast way.

cvc_4

Now add a new Storyboard to the project, disable Autolayout and update the project to use iOS 6.0+ and the storyboards.

cvc_5 cvc_6

At this point you can create a new Class called SceneViewController as subclass of CocosViewController.
Add the following lines to the controller class.

@interface SceneViewController() <CocosViewControllerDelegate>
@end

@implementation SceneViewController

– (void)viewDidLoad
{
[super viewDidLoad];

self.delegate = self;
}

– (IBAction)dismiss:(id)sender
{
[self removeDirector];

[self.navigationController popViewControllerAnimated:YES];
}

#pragma mark CocosViewControllerDelegate

– (CCScene *)cocosViewControllerSceneToRun:(CocosViewController *)cocosViewController
{
return [CCBReader loadAsScene:@”MainScene”];
}

@end

You can watch at the screenshot.

cvc_7

Now go to the storyboard. Add a navigation controller, a menu view controller with a button and add the SceneViewController.
Link the navigation controller to the menu controller and the menu button to the SceneViewController with a push segue.
Now you only need to create an exit button in the SceneViewController and link to the -dismiss: method of the same controller.

cvc_8

Build and Run. If you followed all the steps you have now Cocos2D inside of a Storyboard app.

I hope you enjoy it and if you have some problems you can write here in the comments or in the Cocos2D forum post.