Come sviluppare una app non-game per iOS e Android in Unity

In questo articolo verranno affrontati i diversi aspetti riguardanti lo sviluppo di una app prettamente non-game con Unity, engine notoriamente usato invece per lo sviluppo di videogiochi e applicativi 3D.
Sono presenti alcuni concetti di base ma anche diversi consigli su come ottimizzare lo sviluppo e trarre beneficio da un editor potente senza inficiare sulle prestazioni dei dispositivi mobile e sull’uso della batteria (battery drain).

Interfaccia utente

Nello sviluppo di una app non-game l’interfaccia utente (UI) è sicuramente l’elemento che fa da padrone per visualizzazione ma anche usabilità. Unity implementa due tipologie di gestione della UI: uno chiamato UGUI e uno, piu recente, chiamato UI Toolkit. Entrambi hanno pro e contro nel loro utilizzo ma una delle caratteristiche comuni è di non aver implementato oggetti che sono notoriamente usati nelle app non-game (ad esempio: caroselli, calendari, finestre modali, etc).
In versione ancora sperimentale è bene citare anche un nuovo framework di Unity chiamato App UI.

Prima di addentrarsi nello sviluppo di componenti custom attraverso la UI di Unity è bene sapere che nell’Asset Store sono presenti diverse collezioni di elementi UI già pronti e ben realizzati, come ad esempio Evo UI che è possibile trovare qui

Camera principale

Qualora non sia necessario renderizzare a schermo nessuna componente 3D è bene eliminare completamente la Camera 3D dalla scena, questo ottimizza moltissimo la fase di rendering a schermo in quanto non vengono implementate le funzionalità di visualizzazione e di post processing della pipeline.

Safe Area

Se in un videogioco normalmente la scena occupa l’intero schermo del dispositivo, in una app non-game è bene capire quanto sia importante il concetto di SafeArea. Su alcuni dispositivi Android o iOS alcune sezioni dello schermo potrebbero non essere visibili o non interagibili (ad esempio in fondo allo schermo, oppure sotto il notch dell’iPhone). E’ buona pratica quindi impostare il canvas degli elementi UI alla dimensione della SafeArea così da evitare che la UI (pulsanti o diciture) siano sempre visibili a schermo, in questo modo:

var safeAreaForUIToolkit = new Rect(Screen.safeArea.x, Screen.height - Screen.safeArea.y, Screen.safeArea.width, Screen.safeArea.height);

Discorso a parte va fatto per la Navigation Bar presente su dispositivi mobile iOS. Si tratta di un’area sopra la SafeArea dove andrebbero posizionati i pulsanti di navigazione dell’app. E’ bene sapere della sua esistenza per gestire al meglio la visualizzazione su dispositivi Apple (se con o senza Navigation Bar). Tale elemento è alto, per convenzione, 69 pixel.

Fullscreen mode

Una delle particolarità di una app non-game è quella che tendenzialmente non deve essere posta in fullscreen come un videogame in quanto deve permettere l’uso della barra degli strumenti di sistema (visibile in Android).
E’ bene quindi impostare la proprietà FullScreen Mode su Window nei Project Settings oppure da codice:

Screen.fullScreen = false;

Motori fisici

Unity implementa di base due motori fisici, uno 3D e uno 2D che permettono di eseguire operazioni fisiche tra GameObject (collisioni, forze, etc). In una app-non game queste funzionalità sono pressoché inutili quindi un ulteriore risparmio di risorse lo si ottiene disattivandoli, nello specifico con:

Physics.simulationMode = SimulationMode.Script; 
Physics2D.simulationMode = SimulationMode2D.Script;

E’ bene ricordare la che disattivazione dei motori fisici non disattiva le funzioni Update e FixedUpdate che invece continuano ad essere eseguite.

FPS

I frame per secondo sono una parte fondamentale per la fluidità dell’app. In Unity è possibile forzare il targetFrameRate a valori desiderati così come lasciare che sia sincronizzato con quello dello schermo. Il consiglio è quello di verificare il valore migliore per la fluidità dell’app, molto spesso però la scelta ricade su 60FPS, impostabili in questo modo:

QualitySettings.vSyncCount = 0;
Application.targetFrameRate = 60;

Update e FixedUpdate

In una app non-game, dove le attività sono concentrate sulle funzioni della UI, è possibile escludere completamente le funzioni Update e FixedUpdate che di fatto vengono eseguite ad ogni frame consumando risorse e batteria. Il consiglio è quelle di eliminarle completamente dagli script dei GameObject in scena.

Timeout dello schermo

Se in un videogame il timeout dello schermo dovrebbe essere sempre disattivato (lo schermo potrebbe spegnersi durante una cutscene ad esempio), in una app-non game è preferibile impostare lo sleepTimeout sul valore di sistema (in modo che si disattivi dopo il tempo definito nelle impostazioni), nel modo seguente:

Screen.sleepTimeout = -2;

On Demand Rendering

Una delle funzionalità meno conosciute di Unity è la possibilità di renderizzare lo schermo solo su richiesta e non in modo continuativo (default). Questa attività si chiama On Demand Rendering e permette di gestire ogni quanti FPS renderizzare la scena. In una app non-game in cui non ci sono in gioco simulazioni o visualizzazioni realtime questo può fare la differenza. Un valore uguale a 1 (default) permette il rendering realtime, valori più alti permettono di renderizzare invece ad intervalli prestabiliti di FPS.
Ad esempio, se gli FPS sono impostati a 60 e si definisce un renderFrameInterval di 6, la scena verrà renderizzata ogni 10 FPS, nel seguente modo:

OnDemandRendering.renderFrameInterval = 6;

Per evitare poi latenze al momento del touch a schermo è necessario reimpostare il valore a 1 così da eseguire un rendering immediato, nel seguente modo:

if (Input.GetMouseButton(0) || (Input.touchCount > 0))
{
Canvas.ForceUpdateCanvases();
UnityEngine.Rendering.OnDemandRendering.renderFrameInterval = 1;
}
else
{
UnityEngine.Rendering.OnDemandRendering.renderFrameInterval = 6;
}

Nascondere l’input field della tastiera di sistema

Una delle particolarità della tastiera a schermo di iOS è quella che una volta aperta mostra una casella di testo sopra di essa in cui scrivere il contenuto della textbox che si vuole riempire. E’ una funzionalità utile ma non è un comportamento di sistema che invece è stato implementato da Unity per facilitare l’inserimento di testi. E’ notoriamente fastidioso e può essere eliminato impostando la proprietà shouldHideMobileInput di tutti i componenti InputField e TMP_InputField della scena su true, come di seguito:

List fields = FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None).ToList();
foreach (TMPro.TMP_InputField field in fields)
{
field.shouldHideMobileInput = true;
}

Esiste anche un parametro TouchScreenKeyboard.hideInput da impostare a true, ma sembra che nelle ultime versione di Unity questo non abbia alcun effetto.

Mettere in evidenza l’input box al focus

Una delle particolarità delle app native è quella di implementare una sistema di messa a fuoco (al centro dello schermo) delle caselle Input box, questo per facilitare l’inserimento di testo e renderlo visibile durante la digitazione. Unity purtroppo non lo implementa e deve essere realizzato da codice sfruttando la dimensione del Canvas di appartenenza e la dimensione della Input box interessata.

Notifiche in app

Una delle funzionalità che di certo sono indispensabili nello sviluppo di una app non-game è quella dell’invio delle notifiche. Unity mette a disposizione un potente sistema di notifiche che gestisce indipendentemente sia quelle di Android che quelle di iOS ma anche un potente framework che le gestisce in modo unificato.
Qui un nostro articolo di approndimento.

Gestione della galleria fotografica

Una delle funzionalità che può essere richiesta da una app non-game è quella di poter accedere alla camera e alla galleria fotografica (rullino) di sistema. Questa funzionalità non è implementata da Unity in modo nativo in quanto necessita di chiamate a basso livello di sistema. In nostro aiuto viene un utilissimo asset gratuito chiamato “Native Gallery for Android & iOS” scaricabile qui.

Gestione dei file di sistema

Un’altra funzionalità utile in app non-game è quella di poter accedere ai file di sistema (ad esempio per recuperare un file dalla cartella download). Anche in questo caso la funzionalità non è nativa in Unity ed è possibile implementarla attraverso l’asset gratuito “Native file Picker for Android & iOS” scaricabile qui.

Feedback aptici

Funzionalità sicuramente utile e interessante da implementare in una app non-game è quella dei feedback aptici (o in generale le vibrazioni). Tale funzionalità permette un riscontro non solo visivo di attività svolte dalla app.
Sia Android che iOS permettono questo tipo di funzionalità ma non sono implementate nativamente da Unity necessitando quindi di un asset gratuito chiamato “Mobile Haptic Feedback” scaricabile qui.

Dimensione della build

Uno degli aspetti da non sottovalutare è quello delle dimensione, in MB, dell’applicativo generato.

La prima ottimizzazione che è possibile fare è quella di eliminare completamente i pacchetti di default che Unity installa e che nel progetto non sono utilizzati. Un esempio potrebbe essere il Visual Scripting, oppure il Multiplayer, oppure il nuovo Input System o addirittura la URP (Universal Rendering Pipeline) in quanto la app potrebbe usare solo la componente UGUI. Il consiglio è di rimuovere man mano i pacchetti e verificare che la app non generi errori di compilazione o di visualizzazione a runtime.

Un secondo elemento importante per la compressione della build finale è il parametro Project Settings -> Player -> Managed Stripping Level che di default è impostato a Minimal. Questo parametro ottimizza la generazione del codice compilato e può essere impostato in modo graduale su diversi parametri, il consiglio è di provare le diverse opzioni.

Copyright © Desdinova ® / PIVA 03799780162 / Non è una testata giornalistica.
Tutti i diritti riservati ai legittimi proprietari, anche ove non citati.