• IT
betterdocs-cat-icon 1-svg

Qualcosa è andato storto?

Condividi con noi la tua opinione per migliorare la nostra documentazione.

    Getting Started

    • Introduzione Instant Developer Cloud
    • Composizione della piattaforma
    • Struttura dei progetti
    • La programmazione relazionale
    • Apprendere l’uso di Instant Developer Cloud

    Struttura di un'applicazione

    • Introduzione (applicazione e sessione)
    • Le videate
    • Classi e librerie
    • Risorse e CSS
    • I pacchetti
    • Programmazione asincrona

    Struttura del database

    • Introduzione (struttura del database)
    • Definizione degli schemi relazionali
    • Scrittura di query ed esecuzione di comandi
    • Gestione dei database nel cloud
    • Il Cloud Connector

    Document Orientation

    • Introduzione Document Orientation
    • Definire Documenti e Collection
    • Utilizzo dei documenti
    • Estensione dei documenti

    Datamap

    • Introduzione Datamap
    • Creazione di liste di documenti
    • Modifica dei documenti con videate di dettaglio
    • Datamap innestate e ricorsive

    IonicUI

    • Introduzione IonicUi
    • Le pagine IonicUI
    • Definire il contenuto delle pagine
    • Il page controller
    • Il metodo app.popup
    • Videate come elementi visuali
    • Personalizzazione di IonicUI
    • Configurazione dei ruoli e degli accessi

    Pannelli e Griglie

    • Introduzione (Pannelli e Griglie)
    • Anatomia di un pannello
    • I pannelli a runtime

    Web API e file system

    • Introduzione Web API
    • Il file system
    • Consumare Web API
    • Esporre Web API
    • Web API in formato OData
    • Utilizzare Web API Instant Developer Foundation
    • Web API in formato OpenAPI

    Sincronizzazione

    • Introduzione sistema di sincronizzazione
    • Scambio di messaggi in tempo reale
    • Document Orientation Remota
    • Sincronizzazione del database offline

    Debugging e Test

    • Introduzione Debugging e Test
    • Strumenti e tecniche di debug
    • Test automatico delle applicazioni

    Traduzioni

    • Introduzione (traduzioni)
    • Processo di traduzione
    • Funzionamento del framework di localizzazione
    • Localizzazione di numeri e date

    Integrazioni di componenti esterni

    • Introduzione (integrazioni di componenti esterni)
    • Integrazione di componenti JavaScript
    • Integrazione di librerie di back-end
    • Integrazione di un plugin Cordova

    Launcher e Pubblicazione

    • Introduzione Launcher
    • I plugin nativi
    • Test delle applicazioni nei launcher
    • Pubblicazione sugli store
    • Configurazioni per gli store
    • Fase di build e di invio
    • Gestione dell’applicazione

    Analitiche e Feedback

    • Introduzione Analytics e Feedback
    • Installazione ed uso di Analytics
    • Raccolta dei feedback degli utenti

    Server di Produzione

    • Introduzione server di produzione
    • I server di Instant Developer Cloud
    • I server My Cloud
    • I server Self Managed
    • Tabella comparativa

    Cloud Connector

    • Cos’è il Cloud Connector
    • Installazione Cloud Connector
    • Configurazione
    • Installazione come servizio
    • Esempio di utilizzo
    • Controllo remoto
    • Note

    Team Works

    • PerchĂŠ non basta GitHub?
    • Team Works: concetti base
    • Organizzazione del lavoro consigliata
    • Risoluzione dei problemi relativi a Team Works
    • Domande sull’utilizzo di Team Works

    Manuale PWA

    • Cos’è una PWA?
    • Creazione di una PWA su Instant Developer Cloud
    • Life Cycle
    • Installazione PWA
    • FunzionalitĂ 
    • Plugin
    View Categories

    Scambio di messaggi in tempo reale

    Contenuti
    • Inviare e ricevere messaggi
    • I topics
      • Topics come canali di interesse
      • Topics delle sessioni locali
        • Variazione dei topics durante una sessione
    • I messaggi permanenti
      • Gestione dei messaggi permanenti
      • Messaggi permanenti: quando utilizzarli?
    • Test della sincronizzazione
      • Test con applicazione in produzione
    • Usare il sistema di log della sincronizzazione

    Dopo aver visto come connettere le varie sessioni al sistema, illustriamo il comportamento di base della sincronizzazione: lo scambio di messaggi tra sessioni.

    Per mostrare i vari passaggi, utilizzeremo il seguente caso: si hanno un’applicazione che ammette una chiamata REST per acquisire lo stato del segnale di allarme di una centralina, e delle sessioni di visualizzazione che mostrano lo stato di una specifica centralina o di un insieme di centraline collocate nel medesimo sito.

    In questo caso, la sessione che gestisce la chiamata REST deve avvisare del cambiamento le sessioni di visualizzazione. Questo deve avvenire solo per le sessioni che visualizzano lo stato della centralina in cui è avvenuto l’evento.

    Inviare e ricevere messaggi #

    Per inviare un messaggio è sufficiente utilizzare il metodo sendMessage dell’oggetto app.sync. Ad esempio la sessione REST che riceve i dati dell’allarme potrebbe inviarli alle altre sessioni tramite questa riga di codice:

    app.sync.sendMessage({
      topics:”1212”, 
      body:{sensor:”W1”, status:”ON”},
      ttl:0
    });

    Il primo parametro sono i topics del messaggio, che spiegheremo nel paragrafo successivo, il secondo è il contenuto (body) del messaggio e l’ultimo (ttl) è il tempo di vita del messaggio.

    Come contenuto del messaggio possiamo usare un qualunque oggetto JavaScript, mentre il tempo di vita è un numero intero che rappresenta il numero di secondi per cui il messaggio deve essere memorizzato nel caso non sia possibile consegnarlo subito alle sessioni offline. Se è pari a 0 o viene omesso, il messaggio viene inviato solo alle sessioni attualmente collegate.

    Il messaggio viene notificato tramite l’evento app.sync.onMessage, che ne contiene i dati. Per intercettare il messaggio ed aggiornare l’interfaccia utente si può usare la seguente riga di codice:

    app.sync.onMessage = function (message)
    {
      App.Pages.postMessage(app, message);
    };

    Come abbiamo visto nel capitolo relativo al framework IonicUI, il metodo postMessage invia un messaggio alla videata attiva del page controller. A questo punto la videata può intercettare l’evento onMessage ed aggiornare gli elementi visuali di conseguenza. Si ricorda che impostando message.bc = true, il messaggio verrà consegnato a tutte le videate aperte e non solo a quella attiva.

    I topics #

    Il sistema di sincronizzazione non deve inviare tutti i messaggi ad ogni sessione collegata, ma occorre effettuare una selezione. Prima di poter scambiare i messaggi, è necessario comprendere come avviene il filtro del sistema di sincronizzazione, in modo da poter inviare ad ogni sessione solo i messaggi che la riguardano.

    Per poter effettuare questa selezione, è necessario familiarizzare con il concetto di topics di un messaggio e di topics della sessione. 

    I topics di un messaggio rappresentano i suoi argomenti e sono rappresentati come oggetto JavaScript. I topics della sessione sono gli argomenti a cui una determinata sessione dichiara di essere interessata, anch’essi espressi come oggetto JavaScript.

    In questo modo un messaggio viene inviato ad una sessione solo se i topics del messaggio sono compatibili con i topics della sessione.

    Siccome i topics sono oggetti JavaScript, essi possono essere composti a piĂš livelli, sia tramite array, che con valori singoli.

    Nell’esempio delle centraline, i topics del messaggio di cambio stato dell’allarme devono contenere almeno il codice della centralina. Ogni sessione può dichiarare a quale centralina è interessata usando il suo codice come topics della sessione di sincronizzazione. Se quindi i topics del messaggio sono “1212”, i topics delle sessioni che intercettano il messaggio possono essere definiti come segue:

    app.sync.topics = “1212”;

    Siccome le centraline sono raggruppate in diversi siti, una sessione può visualizzare lo stato di tutte le centraline di un sito. Per farlo essa può impostare come topics della sessione un array che contiene tutti i codici delle centraline del sito, come mostrato nella riga di codice  seguente:

    app.sync.topics = [“1212”, “1225”, “1201”, ...];

    Una soluzione alternativa è quella di usare come topics del messaggio sia il codice della centralina che quello del sito, ad esempio:

    app.sync.sendMessage({topics:{box:”1212”, site:”east”}, ...});

    In questo modo le sessioni di visualizzazione potrebbero “sottoscrivere” uno o più “canali” di interesse: alcune potrebbero essere interessate ai box, altre ai siti. In questo caso una sessione deve definire a cosa è interessata, inserendo un asterisco nelle proprietà rimanenti. Vediamo alcuni esempi:

    // Mi interessa solo una centralina 1212, senza considerare il sito
    app.sync.topics = {box:”1212”, site:”*”};
    
    // Mi interessano tutte le centraline di un sito
    app.sync.topics = {box:”*”, site:”east”};
    
    // Mi interessano varie centraline (anche di siti diversi)
    app.sync.topics = {box:[”1212”,“2519”], site:”*”};
    
    // Mi interessano varie centraline, di un unico sito
    app.sync.topics = {box:[”1212”,“1201”], site:”east”};
    
    // Mi interessano piĂš siti
    app.sync.topics = {box:”*”, site:[”east”, “west”]};

    È possibile che una sessione sia interessata a tutti i messaggi; in tal caso può usare come topics il carattere asterisco. In generale questo non deve avvenire perchÊ inviare tutti i messaggi a tutte le sessioni può peggiorare le performance e minare la privacy del sistema.

    Topics come canali di interesse #

    L’uso di un oggetto JavaScript con diverse proprietĂ  come topics dei messaggi e delle sessioni può essere interpretato come la dichiarazione dei possibili “canali” a cui le varie sessioni possono dichiarare di essere interessate. 

    In un sistema informativo complesso, infatti, si potrebbero scambiare messaggi relativi a diverse entità, anche completamente indipendenti. Ad esempio, oltre al sistema degli allarmi, nello stesso sistema informativo può essere presente lo scambio di messaggi relativi al decollo o all’atterraggio di aerei negli aeroporti.

    In questo caso si possono definire due canali di interesse: le centraline e i voli. Per quanto riguarda le centraline, i dati importanti sono il codice e il sito, mentre per i voli il codice dell’aereo e quello dell’aeroporto.

    Se si invia un messaggio relativo ad una centralina verranno usati i seguenti topics:

    app.sync.sendMessage({topics:{alarm:{box:”1212”, site:”east”}, ...});

    Mentre per un volo:

    app.sync.sendMessage({topics:{flight:{plane:”UK1234”, airport:”BLQ”},...});

    Le sessioni interessate agli allarmi sottoscriveranno solo il canale allarmi. Ad esempio:

    app.sync.topics = {alarm:{box:”*”, site:[”east”, “west”]}};

    Mentre quelle interessate agli aeroporti sottoscriveranno solo il canale voli. Ad esempio:

    app.sync.topics = {flight:{plane:”*”, airport:”BLQ”}};

    Se una sessione fosse interessata sia ad aeroporti che ad allarmi potrebbe avere come topics quanto segue:

    app.sync.topics = {flight:{plane:”*”, airport:”BLQ”},
                       alarm:{box:”*”, site:”east”}};

    Topics delle sessioni locali #

    Le sessioni locali definiscono i topics come tutte le sessioni nel cloud, tuttavia esse entrano nel sistema di sincronizzazione per mezzo della sessione proxy ad esse collegata. Quando una sessione locale apre la connessione, essa passa i suoi topics alla sessione proxy, che può cambiarli a suo piacimento. La sessione locale quindi riceverà i messaggi relativi ai topics della sessione proxy e non ai suoi.

    Questo funzionamento serve come validazione dei topics della sessione locale rispetto al sistema cloud. Se ad esempio viene aperta una connessione che utilizza come topics l’ID dell’utente della sessione locale, può essere utile modificare i topics della sessione proxy in funzione dei dati che tale utente deve vedere. Nell’evento onConnect della sessione proxy, dopo aver verificato che l’utente sia valido, si possono modificare i topics in modo da inviare alla sessione locale non solo i messaggi che riguardano direttamente l’utente, ma anche quelli che riguardano altre entità che l’utente può vedere.

    Immaginiamo, ad esempio di voler gestire un sistema di messaggistica in cui è possibile inviare messaggi fra due utenti oppure agli utenti di un gruppo, come avviene ad esempio in WhatsApp.

    Il messaggio tra due utenti può essere inviato con i seguenti topics:

    app.sync.sendMessage({topics:{sender:”ute0”, receiver:”ute1”}, ...});

    Mentre il messaggio relativo inviato in gruppo potrebbe avere i seguenti topics:

    app.sync.sendMessage({topics:{sender:”ute0”, receiver:”grp3”}, ...});

    Quando una sessione locale apre la connessione, essa si può presentare con i seguenti topics:

    app.sync.topics = “ute0”;

    A questo punto, in funzione dei gruppi a cui l’utente è iscritto, la sessione proxy può modificare i topics come segue:

    app.sync.topics = [
      {sender:“ute0”, receiver:”*”}, // messaggi inviati da me
      {sender:“*”, receiver:”ute0”}, // messaggi inviati a me
      {sender:“*”, receiver:”grp3”}, // messaggi inviati al gruppo 3
      {sender:“*”, receiver:”grp555”}, // messaggi inviati al gruppo 555
      â€Ś 
    };

    In questo modo la sessione locale riceve i messaggi inviati dall’utente, quelli inviati all’utente e quelli inviati a tutti i gruppi a cui l’utente è iscritto.

    Variazione dei topics durante una sessione #

    Abbiamo visto che i topics di una sessione locale vengono inviati alla corrispondente proxy all’apertura in modo che l’evento onConnect possa gestirli. 

    È possibile che, in seguito, la sessione locale voglia modificare i suoi topics senza dover chiudere e riaprire la connessione. 

    Per ottenere questo risultato la sessione locale deve modificare i suoi topics e poi usare il metodo app.sync.notifyTopicsChanged che invia i topics alla sessione proxy senza resettare la connessione. Nella sessione proxy viene notificato l’evento onTopicsChanged in modo che essa possa gestire la variazione. 

    I messaggi permanenti #

    Abbiamo visto che il terzo parametro della funzione sendMessage rappresenta il tempo, misurato in secondi, per cui il messaggio rimane ricevibile da una sessione locale che si collega dopo che il messaggio è stato inviato. 

    Al contrario, le sessioni collegate direttamente al server nel cloud (sessioni online) non ricevono i messaggi inviati prima dell’inizio della sessione.

    Questa differenza nasce dal fatto che una sessione online all’avvio può analizzare l’intero stato del sistema leggendo direttamente il database nel cloud. Inoltre, essendo in esecuzione nel server, per definizione essa rimane connessa alla sincronizzazione fino a che non termina. Ecco perché nelle sessioni online sono importanti solo i messaggi che arrivano dopo l’avvio.

    Invece per una sessione locale è più difficile leggere l’intero stato del sistema perché essa non è connessa al database nel cloud. Inoltre, mentre rimane attiva, la sessione locale può connettersi e disconnettersi dalla sincronizzazione varie volte a causa dello stato della rete cellulare. Per le sessioni locali è quindi essenziale ricevere i messaggi inviati anche quando erano disconnesse, altrimenti potrebbero perderli senza venirne a conoscenza. Da qui la necessità dei cosiddetti messaggi permanenti.

    Gestione dei messaggi permanenti #

    I messaggi permanenti vengono memorizzati in una tabella del database indicato al sistema di sincronizzazione tramite la proprietĂ  app.sync.dataStore. La tabella, di nome z_sync, viene creata e gestita automaticamente dal sistema.

    La tabella z_sync viene creata sia nei device che nel database nel cloud. Nei device essa serve per memorizzare i messaggi inviati tramite il dispositivo mentre questo è offline. Essi verranno consegnati all’apertura della connessione e poi cancellati dal database. 

    Nel cloud, la tabella z_sync memorizza i messaggi permanenti di tutte le sessioni non appena essi vengono consegnati, cancellandoli solo quando diventano piÚ vecchi del timeout. In questo modo, quando una sessione locale si connette, la tabella z_sync nel cloud viene scansionata per trovare i messaggi a cui la sessione è interessata che devono ancora essere consegnati.

    Messaggi permanenti: quando utilizzarli? #

    Finora abbiamo visto come configurare ed inviare messaggi di base tramite il sistema di sincronizzazione. Nei paragrafi seguenti vedremo come applicare la sincronizzazione alla gestione dei documenti, in cui i messaggi scambiati non sono piĂš semplici oggetti JavaScript, ma documenti completi.

    Non è quindi consigliabile utilizzare la sincronizzazione di base per impostare il proprio sistema di scambio messaggi; il metodo migliore è sempre quello di utilizzare la sincronizzazione applicata ai documenti come illustrato nel paragrafo Document Orientation Remota.

    Per questa ragione la gestione dei messaggi permanenti viene disabilitata per default al livello dei messaggi di base. Se si desidera utilizzare i messaggi permanenti di base, è necessario impostare options.skip = false nell’evento onConnect.

    Test della sincronizzazione #

    Una volta completate la configurazione e le funzioni di scambio messaggi, il sistema di sincronizzazione deve essere testato. L’IDE possiede una modalitĂ  di esecuzione delle applicazioni chiamata Anteprima Back End – Front End, abbreviata come FEBE, in grado di eseguire contemporaneamente due sessioni: una in modalitĂ  locale e la seconda in modalitĂ  online.

    La modalità FEBE si attiva tramite la freccia posta sulla destra del pulsante di anteprima. Una volta attivata, vengono mostrate le opzioni di configurazione, come mostrato nell’immagine seguente:

    660e lgyGPXOk7Dex1eKDhuDbEfrq1oAYrVAy6bXJLuJwKS88wEir1Fd6yTr1c8uY6oxBQcMz7znNr cawcOXYFmWBJAq VcTOHQrODkEycjUOoGAfl1MKKpURSlp7R1fGvMWojG0hvIRy SKHWdLw Instant Developer

    In questa videata è possibile scegliere l’applicazione del progetto che deve essere usata come front end (sessione locale) e come back end (sessione online). È possibile usare anche la stessa applicazione in entrambi i casi.

    È inoltre possibile scegliere se le sessioni devono essere avviate nel browser o in un dispositivo connesso all’IDE tramite l’applicazione InstaLauncher, ed infine se deve essere attivata la modalitĂ  di debug full trace o meno. 

    Confermando le opzioni, le sessioni verranno attivate. Se si desidera modificare le opzioni, occorre disattivare e riattivare la modalitĂ  FEBE.

    Quando l’applicazione viene lanciata in FEBE, la proprietà app.sync.serverURL della sessione locale viene preimpostata dal framework in modo che si possa connettere alla sessione online corrispondente. Per questa ragione, tale proprietà dovrebbe essere impostata da codice solo se viene trovata vuota.

    Si noti inoltre che la sessione online funge sia da sessione proxy per la sessione locale che da sessione browser per la visualizzazione dei dati del cloud. Per tale sessione, quindi, vengono notificati sia gli eventi onStart che onConnect. 

    Il vantaggio di questa soluzione consiste nel fatto che la sessione browser/proxy può mostrare a video piĂš facilmente gli effetti delle operazioni di sincronizzazione che avvengono tramite la sessione locale. 

    Occorre tenere presente, tuttavia, le possibili interazioni nell’avvio dei due tipi di sessioni. Ad esempio, se la sessione browser imposta una proprietà di sessione come app.loggedUser, e tale proprietà viene usata nell’evento onConnect senza impostarla anche in quel caso, è possibile che l’applicazione funzioni correttamente in modalità FEBE ma fallisca quando viene installata.

    Quando l’applicazione è in funzione in modalità FEBE, possiamo notare che la barra della console dell’IDE mostra contemporaneamente i messaggi delle due sessioni. Quella locale (front end) sulla sinistra, quella online (back end) spostata a destra. Nell’immagine seguente il messaggio “connecting” proviene dal back end, mentre gli altri dal front end.

    fxR0H78V cCVrkZtzvH2g1Z04 XbhL3I7UV T5Duun7own6EeNwk 1ljMskPNW uvs06fdPasRchDCZIanX bEqUzDlDn24LKJR4eDS5hGTcN44 SRnNPrVphhXWIrAVpwMulW7IEz Sye guVbLrg Instant Developer

    Come esempio del sistema di invio e ricezione messaggi è possibile aprire il progetto sync-design-patterns e lanciarlo in anteprima FEBE. Per aprire la videata di test del sistema di scambio messaggi, aprire il menu della sessione locale e scegliere la voce Sending Messages.

    DYuNB9ARiPDaC2yNgFE83ChA4iokGLQZp9ENJL4UysYpLota8YWa9ZX6n7UPrRR0HQNMo1uF1LcwDRt mbYzZppVFHLk8ar1EhbZtYlZT6OQ5ZwayYLfoHcC MbCE3Ak57pTjm9DGIQthdOk5Ah4w Instant Developer

    A questo punto è possibile selezionare i topics del messaggio sulla destra e quelli della sessione di sincronizzazione sulla sinistra. Poi occorre premere il pulsante Subscribe Topics per aggiornare la sessione di sincronizzazione online ed infine provare ad inviare il messaggio dalla sessione locale a quella online. Se il messaggio viene ricevuto, verrĂ  visualizzato nel campo apposito della sessione online, evidenziato tramite un’animazione.

    Si possono fare vari esperimenti provando a variare i topics del messaggio e quelli della sessione di sincronizzazione.

    Test con applicazione in produzione #

    Dopo aver testato la sincronizzazione tramite FEBE, è importante provare il funzionamento nell’ambiente di produzione. La modalità di test consigliata è la seguente:

    1. Attivare il log strutturato delle sessioni impostando la proprietĂ  app.sessionName negli eventi onStart, onConnect e onCommand.
    2. Installare in un server di produzione l’applicazione di back end attivando l’opzione di debug a runtime durante la configurazione dell’installazione.
    3. Eseguire in anteprima offline nell’IDE l’applicazione di front end. Questa modalitĂ   crea una sessione locale nel browser che si connette al back end di sincronizzazione installato nell’ambiente di produzione. 

    Se vengono evidenziati problemi nel back end non rilevati in modalità FEBE, si consiglia di aprire il debug a runtime della sessione proxy a cui la sessione locale in anteprima nell’IDE si è connessa. Tale sessione viene listata nella pagina log strutturato dell’installazione nel server di produzione. Nell’immagine seguente viene evidenziato il pulsante per accedere alla pagina log strutturato di un’installazione tramite la console di Instant Developer Cloud.

    Instant Developer

    SI ricorda che per attivare il log strutturato di un’installazione occorre dare un nome alle sessioni che si desidera tracciare impostando da codice la proprietà app.sessionName. Inoltre occorre attivare la raccolta dei dati di log tramite gli appositi comandi nella pagina del log strutturato della propria installazione.

    L’ultima fase di test della sincronizzazione consiste nell’utilizzare il back end nell’ambiente di produzione e l’applicazione di front end installata su un dispositivo, anche tramite InstaLauncher. Se in questa fase si verificano anomalie non rilevate dalle fasi di test precedenti, si consiglia di utilizzare il debug a runtime della sessione proxy insieme alla raccolta dati di analitica o inviando messaggi di log dal device di front end alla sessione proxy tramite il servizio di log illustrato nel paragrafo successivo.

    Usare il sistema di log della sincronizzazione #

    Il sistema di sincronizzazione di Instant Developer Cloud include alcuni servizi aggiuntivi fra i quali un servizio che permette di inviare messaggi di log da una sessione locale alla corrispondente proxy. Il servizio viene utilizzato nella sessione locale tramite i seguenti metodi:

    app.sync.log.log(...);
    app.sync.log.warn(...);
    app.sync.log.error(...);


    Nella sessione proxy viene notificato l’evento onClientMessage in cui è possibile gestire il messaggio, ad esempio inserendolo in un database o inviandolo ad una applicazione di visualizzazione. Se questo evento non viene gestito, il messaggio appare nel log della sessione proxy ed è quindi leggibile tramite il log strutturato o tramite i log del server.

    Ti è stato utile?
    Aggiornato il 15 Aprile 2024
    Introduzione sistema di sincronizzazioneDocument Orientation Remota
    Contenuti
    • Inviare e ricevere messaggi
    • I topics
      • Topics come canali di interesse
      • Topics delle sessioni locali
        • Variazione dei topics durante una sessione
    • I messaggi permanenti
      • Gestione dei messaggi permanenti
      • Messaggi permanenti: quando utilizzarli?
    • Test della sincronizzazione
      • Test con applicazione in produzione
    • Usare il sistema di log della sincronizzazione

    Caratteristiche

    • PerchĂŠ Instant Developer
    • IDE e Ambiente di Sviluppo
    • Pubblicazione Web & Mobile
    • Software Life Cycle & DevOps
    • Database, Integrazione, Sync
    • Collaboration & Workflow

    Soluzioni

    • Freelance
    • Software House
    • Company IT
    • Casi di successo
    • Applicazioni Sviluppate

    Azienda

    • Chi Siamo
    • Contatti
    • Lavora con noi

    Risorse

    • Documentazione
    • Risorse e Tutorial
    • Blog
    • Starter Kit
    • Pricing
    • Inizia Ora
    Crea un account e Inizia Gratis
    • Seguici su Twitter
    • Seguici su Facebook
    • Seguici su LinkedIn
    • Seguici su YoutTubeSeguici su YouTube
    Questo sito è protetto dalla tecnologia reCAPTCHA Enterprise e si applicano l'Informativa sulla privacy e i Termini di servizio di Google.
    Google Policy | Termini
    Š Pro Gamma - p.iva, c.f. e iscr. Camera di Commercio Bologna 01985091204 - Sede legale Via D'Azeglio, 51 40123 Bologna - Italia Pro Gamma Instant DeveloperŽ è un marchio registrato.
    Privacy Policy | Cookie Policy
    • IT