Procedura dettagliata: Associare una libreria Swift iOS
Importante
Attualmente si sta esaminando l'utilizzo dell'associazione personalizzata nella piattaforma Xamarin. Si prega di prendere questo sondaggio per informare i futuri sforzi di sviluppo.
Xamarin consente agli sviluppatori di dispositivi mobili di creare esperienze per dispositivi mobili native multipiattaforma usando Visual Studio e C#. È possibile usare i componenti dell'SDK della piattaforma iOS predefiniti. In molti casi, tuttavia, si vogliono usare anche SDK di terze parti sviluppati per tale piattaforma, che Xamarin consente di eseguire tramite associazioni. Per incorporare un framework di terze parti Objective-C nell'applicazione Xamarin.iOS, è necessario creare un'associazione Xamarin.iOS per poterla usare nelle applicazioni.
La piattaforma iOS, insieme ai linguaggi nativi e agli strumenti, è in continua evoluzione e Swift è una delle aree più dinamiche del mondo di sviluppo iOS in questo momento. Esistono diversi SDK di terze parti, che sono già stati migrati da Objective-C a Swift e presenta nuove sfide. Anche se il processo di associazione Swift è simile a Objective-C, richiede passaggi aggiuntivi e impostazioni di configurazione per compilare ed eseguire correttamente un'applicazione Xamarin.iOS accettabile per l'AppStore.
L'obiettivo di questo documento è delineare un approccio generale per affrontare questo scenario e fornire una guida dettagliata con un semplice esempio.
Background
Swift è stato inizialmente introdotto da Apple nel 2014 ed è ora nella versione 5.1 con l'adozione da framework di terze parti in rapida crescita. Sono disponibili alcune opzioni per l'associazione di un framework Swift e questo documento descrive l'approccio usando Objective-C l'intestazione dell'interfaccia generata. L'intestazione viene creata automaticamente dagli strumenti Xcode quando viene creato un framework e viene usata come modo per comunicare dal mondo gestito al mondo Swift.
Prerequisiti
Per completare questa procedura dettagliata, è necessario:
- Xcode
- Visual Studio per Mac
- Objective Sharpie
- Interfaccia della riga di comando di AppCenter (facoltativo)
Creare una libreria nativa
Il primo passaggio consiste nel creare un framework Swift nativo con Objective-C l'intestazione abilitata. Il framework viene in genere fornito da uno sviluppatore di terze parti e ha l'intestazione incorporata nel pacchetto nella directory seguente: FrameworkName.framework>/Headers/<FrameworkName-Swift.h>.<
Questa intestazione espone le interfacce pubbliche, che verranno usate per creare metadati di associazione Xamarin.iOS e generare classi C# che espongono i membri del framework Swift. Se l'intestazione non esiste o ha un'interfaccia pubblica incompleta (ad esempio, non vengono visualizzate classi/membri) sono disponibili due opzioni:
- Aggiornare il codice sorgente Swift per generare l'intestazione e contrassegnare i membri necessari con
@objc
l'attributo - Creare un framework proxy in cui è possibile controllare l'interfaccia pubblica e il proxy di tutte le chiamate al framework sottostante
In questa esercitazione, il secondo approccio viene descritto come presenta meno dipendenze dal codice sorgente di terze parti, che non è sempre disponibile. Un altro motivo per evitare il primo approccio è lo sforzo aggiuntivo necessario per supportare le modifiche future del framework. Dopo aver iniziato ad aggiungere modifiche al codice sorgente di terze parti, si è responsabili del supporto di queste modifiche e di unirle potenzialmente a ogni aggiornamento futuro.
In questa esercitazione, ad esempio, viene creata un'associazione per Gigya Swift SDK :
Aprire Xcode e creare un nuovo framework Swift, che sarà un proxy tra il codice Xamarin.iOS e il framework Swift di terze parti. Fare clic su File > Nuovo > progetto e seguire la procedura guidata:
Scaricare gigya xcframework dal sito Web per sviluppatori e decomprimerlo. Al momento della scrittura, la versione più recente è Gigya Swift SDK 1.5.3
Selezionare SwiftFrameworkProxy da Esplora file di progetto e quindi selezionare la scheda Generale
Trascinare e rilasciare il pacchetto Gigya.xcframework nell'elenco Xcode Frameworks and Libraries nella scheda Generale selezionare l'opzione Copia elementi se necessario durante l'aggiunta del framework:
Verificare che il framework Swift sia stato aggiunto al progetto; in caso contrario, le opzioni seguenti non saranno disponibili.
Assicurarsi che l'opzione Non incorporare sia selezionata, che verrà controllata manualmente in un secondo momento:
Assicurarsi che l'opzione Compila Impostazioni Always Embed Swift Standard Libraries, che include librerie Swift con il framework sia impostata su No. Sarà successivamente controllato manualmente, che Swift dylibs è incluso nel pacchetto finale:
Assicurarsi che l'opzione Abilita bitcode sia impostata su No. A partire dal momento Xamarin.iOS non include Bitcode, mentre Apple richiede tutte le librerie per supportare le stesse architetture:
È possibile verificare che nel framework risultante sia disabilitata l'opzione Bitcode eseguendo il comando terminale seguente sul framework:
otool -l SwiftFrameworkProxy.framework/SwiftFrameworkProxy | grep __LLVM
L'output deve essere vuoto in caso contrario si desidera esaminare le impostazioni del progetto per la configurazione specifica.
Assicurarsi che l'opzione Objective-C Nome intestazione interfaccia generata sia abilitata e specifica un nome di intestazione. Il nome predefinito è <FrameworkName-Swift.h>:
Suggerimento
Se questa opzione non è disponibile, assicurarsi prima di tutto di aggiungere un
.swift
file al progetto come illustrato di seguito, quindi tornare a e l'impostazioneBuild Settings
deve essere individuabile.Esporre i metodi desiderati e contrassegnarli con l'attributo
@objc
e applicare regole aggiuntive definite di seguito. Se si compila il framework senza questo passaggio, l'intestazione generata Objective-C sarà vuota e Xamarin.iOS non sarà in grado di accedere ai membri del framework Swift. Esporre la logica di inizializzazione per l'SDK Gigya Swift sottostante creando un nuovo file SwiftFrameworkProxy.swift e definendo il codice seguente:import Foundation import UIKit import Gigya @objc(SwiftFrameworkProxy) public class SwiftFrameworkProxy : NSObject { @objc public func initFor(apiKey: String) -> String { Gigya.sharedInstance().initFor(apiKey: apiKey) let gigyaDomain = Gigya.sharedInstance().config.apiDomain let result = "Gigya initialized with domain: \(gigyaDomain)" return result } }
Alcune note importanti sul codice precedente:
- L'importazione del
Gigya
modulo qui dall'SDK Gigya di terze parti originale consente l'accesso a qualsiasi membro del framework. - Classe Mark SwiftFrameworkProxy con l'attributo
@objc
che specifica un nome. In caso contrario, verrà generato un nome univoco illeggibile, ad esempio_TtC19SwiftFrameworkProxy19SwiftFrameworkProxy
. Il nome del tipo deve essere chiaramente definito perché verrà usato in un secondo momento dal nome. - Ereditare la classe proxy da
NSObject
, in caso contrario non verrà generata nel Objective-C file di intestazione. - Contrassegnare tutti i membri da esporre come
public
.
- L'importazione del
Modificare la configurazione della compilazione dello schema da Debug a Release. A tale scopo, aprire la finestra di dialogo Xcode Target > Edit Scheme (Schema di modifica destinazione Xcode>) e quindi impostare l'opzione Build Configuration (Configurazione compilazione) su Release (Rilascio):
A questo punto, il framework è pronto per la creazione. Compilare il framework sia per le architetture del simulatore che per le architetture dei dispositivi e quindi combinare gli output come un singolo bundle di framework binario (
.xcframework
). Eseguire la compilazione con i comandi seguenti:xcodebuild -project "Swift/SwiftFrameworkProxy/SwiftFrameworkProxy.xcodeproj" archive \ -scheme "SwiftFrameworkProxy" \ -configuration Release \ -archivePath "build/SwiftFrameworkProxy-simulator.xcarchive" \ -destination "generic/platform=iOS Simulator" \ -derivedDataPath "build" \ -IDECustomBuildProductsPath="" -IDECustomBuildIntermediatesPath="" \ ENABLE_BITCODE=NO \ SKIP_INSTALL=NO \ BUILD_LIBRARY_FOR_DISTRIBUTION=YES
xcodebuild -project "Swift/SwiftFrameworkProxy/SwiftFrameworkProxy.xcodeproj" archive \ -scheme "SwiftFrameworkProxy" \ -configuration Release \ -archivePath "build/SwiftFrameworkProxy-ios.xcarchive" \ -destination "generic/platform=iOS" \ -derivedDataPath "build" \ -IDECustomBuildProductsPath="" -IDECustomBuildIntermediatesPath="" \ ENABLE_BITCODE=NO \ SKIP_INSTALL=NO \ BUILD_LIBRARY_FOR_DISTRIBUTION=YES
Suggerimento
Vedere altre informazioni sulla creazione di framework binari
Suggerimento
Se si dispone di un'area di lavoro anziché di un progetto, compilare l'area di lavoro e specificare la destinazione come parametro obbligatorio. Si vuole anche specificare una directory di output perché per le aree di lavoro questa directory sarà diversa da quella per le compilazioni del progetto.
Suggerimento
È anche possibile usare lo script helper per compilare il framework per tutte le architetture applicabili o semplicemente compilarlo dal simulatore di cambio Xcode e dal dispositivo nel selettore di destinazione.
Esistono due archivi con i framework generati, uno per ogni piattaforma, combinarli come un singolo bundle di framework binario da incorporare in un progetto di associazione Xamarin.iOS in un secondo momento. Per creare un bundle di framework binario, che combina entrambe le architetture, è necessario eseguire i passaggi seguenti. Il pacchetto con estensione xcarchive è solo una cartella in modo da poter eseguire tutti i tipi di operazioni, ad esempio l'aggiunta, la rimozione e la sostituzione dei file:
Creare un
xcframework
oggetto con i framework predefiniti in precedenza negli archivi:xcodebuild -create-xcframework \ -framework "build/SwiftFrameworkProxy-simulator.xcarchive/Products/Library/Frameworks/SwiftFrameworkProxy.framework" \ -framework "build/SwiftFrameworkProxy-ios.xcarchive/Products/Library/Frameworks/SwiftFrameworkProxy.framework" \ -output "build/SwiftFrameworkProxy.xcframework"
Suggerimento
Se si vuole supportare solo una singola piattaforma (ad esempio, si sta creando un'app, che può essere eseguita solo in un dispositivo) è possibile ignorare il passaggio per creare la libreria .xcframework e usare il framework di output della build del dispositivo in precedenza.
Suggerimento
È anche possibile usare lo script helper per creare il file con estensione xcframework, che automatizza tutti i passaggi precedenti.
Preparare i metadati
A questo punto, è necessario avere il file xcframework con l'intestazione dell'interfaccia Objective-C generata pronta per essere utilizzata da un'associazione Xamarin.iOS. Il passaggio successivo consiste nel preparare le interfacce di definizione dell'API, usate da un progetto di associazione per generare classi C#. Queste definizioni possono essere create manualmente o automaticamente dallo strumento Objective Sharpie e dal file di intestazione generato. Usare Sharpie per generare i metadati:
Scaricare l'ultimo strumento Objective Sharpie dal sito Web dei download ufficiali e installarlo seguendo la procedura guidata. Al termine dell'installazione, è possibile verificarlo eseguendo il comando sharpie:
sharpie -v
Generare metadati usando sharpie e il file di intestazione generato automaticamente Objective-C :
sharpie bind --sdk=iphoneos16.4 --output="XamarinApiDef" --namespace="Binding" --scope="build/SwiftFrameworkProxy.xcframework/ios-arm64/SwiftFrameworkProxy.framework/Headers/" "build/SwiftFrameworkProxy.xcframework/ios-arm64/SwiftFrameworkProxy.framework/Headers/SwiftFrameworkProxy-Swift.h"
L'output riflette il file di metadati generato: ApiDefinitions.cs. Salvare questo file per il passaggio successivo per includerlo in un progetto di associazione Xamarin.iOS insieme ai riferimenti nativi:
Parsing 1 header files... Binding... [write] ApiDefinitions.cs
Lo strumento genererà i metadati C# per ogni membro esposto Objective-C , che sarà simile al codice seguente. Come si può notare, può essere definito manualmente perché ha un formato leggibile e un mapping semplice dei membri:
[Export ("initForApiKey:")] string InitForApiKey (string apiKey);
Suggerimento
Il nome del file di intestazione può essere diverso se sono state modificate le impostazioni Xcode predefinite per il nome dell'intestazione. Per impostazione predefinita, ha il nome di un progetto con il suffisso -Swift . È sempre possibile controllare il file e il relativo nome passando alla cartella delle intestazioni del pacchetto framework.
Suggerimento
Come parte del processo di automazione, è possibile usare lo script helper per generare automaticamente i metadati dopo la creazione di .xcframework.
Creare una libreria di associazioni
Il passaggio successivo consiste nel creare un progetto di associazione Xamarin.iOS usando il modello di associazione di Visual Studio, aggiungere metadati necessari, riferimenti nativi e quindi compilare il progetto per produrre una libreria di consumo:
Aprire Visual Studio per Mac e creare un nuovo progetto di libreria di binding Xamarin.iOS, assegnargli un nome, in questo caso SwiftFrameworkProxy.Binding e completare la procedura guidata. Il modello di associazione Xamarin.iOS si trova nel percorso seguente: Libreria di binding della libreria >iOS: >
Eliminare il file di metadati esistente ApiDefinition.cs perché verrà sostituito completamente con i metadati generati dallo strumento Objective Sharpie.
Copiare i metadati generati da Sharpie in uno dei passaggi precedenti, selezionare l'azione di compilazione seguente nella finestra delle proprietà: ObjBindingApiDefinition per il file ApiDefinitions.cs e ObjBindingCoreSource per il file StructsAndEnums.cs:
I metadati stessi descrivono ogni Objective-C classe esposta e membro usando il linguaggio C#. È possibile visualizzare la definizione di intestazione originale Objective-C insieme alla dichiarazione C#:
// @interface SwiftFrameworkProxy : NSObject [BaseType (typeof(NSObject))] interface SwiftFrameworkProxy { // -(NSString * _Nonnull)initForApiKey:(NSString * _Nonnull)apiKey __attribute__((objc_method_family("none"))) __attribute__((warn_unused_result)); [Export ("initForApiKey:")] string InitForApiKey (string apiKey); }
Anche se si tratta di un codice C# valido, non viene usato così come è, ma viene usato dagli strumenti Xamarin.iOS per generare classi C# in base a questa definizione di metadati. Di conseguenza, anziché l'interfaccia SwiftFrameworkProxy si ottiene una classe C# con lo stesso nome, che può essere creata un'istanza dal codice Xamarin.iOS. Questa classe ottiene metodi, proprietà e altri membri definiti dai metadati, che verranno chiamati in modo C#.
Aggiungere un riferimento nativo al bundle del framework binario generato in precedenza, nonché a ogni dipendenza di tale framework. In questo caso, aggiungere riferimenti nativi del framework SwiftFrameworkProxy e Gigya al progetto di associazione:
- Per aggiungere riferimenti al framework nativo, aprire il finder e passare alla cartella con i framework. Trascinare e rilasciare i framework nella posizione Riferimenti nativi nella Esplora soluzioni. In alternativa, è possibile usare l'opzione di menu di scelta rapida nella cartella Riferimenti nativi e fare clic su Aggiungi riferimento nativo per cercare i framework e aggiungerli:
Aggiornare le proprietà di ogni riferimento nativo e controllare tre opzioni importanti:
- Imposta collegamento intelligente = true
- Impostare Force Load = false
- Impostare l'elenco dei framework usati per creare i framework originali. In questo caso ogni framework ha solo due dipendenze: Foundation e UIKit. Impostarlo sul campo Framework:
Se sono presenti flag del linker aggiuntivi da specificare, impostarli nel campo flag del linker. In questo caso, tenerlo vuoto.
Specificare flag del linker aggiuntivi quando necessario. Se la libreria di cui si sta eseguendo l'associazione espone solo Objective-C le API ma internamente usa Swift, è possibile che si verifichino problemi come:
error MT5209 : Native linking error : warning: Auto-Linking library not found for -lswiftCore error MT5209 : Native linking error : warning: Auto-Linking library not found for -lswiftQuartzCore error MT5209 : Native linking error : warning: Auto-Linking library not found for -lswiftCoreImage
Nelle proprietà del progetto di associazione per la libreria nativa è necessario aggiungere i valori seguenti ai flag del linker:
L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator/ -L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos -Wl,-rpath -Wl,@executable_path/Frameworks
Le prime due opzioni (
-L ...
quelle) indicano al compilatore nativo dove trovare le librerie swift. Il compilatore nativo ignorerà le librerie che non hanno l'architettura corretta, il che significa che è possibile passare la posizione sia per le librerie del simulatore che per le librerie di dispositivi contemporaneamente, in modo che funzioni sia per le compilazioni del simulatore che per le compilazioni dei dispositivi (questi percorsi sono corretti solo per iOS; per tvOS e watchOS devono essere aggiornati). Uno svantaggio è che questo approccio richiede che il codice Xcode corretto si trova in /Application/Xcode.app, se il consumer della libreria di binding ha Xcode in un percorso diverso, non funzionerà. La soluzione alternativa consiste nell'aggiungere queste opzioni negli argomenti mtouch aggiuntivi nelle opzioni di compilazione iOS del progetto eseguibile (--gcc_flags -L... -L...
). La terza opzione rende il linker nativo archiviare il percorso delle librerie swift nel file eseguibile, in modo che il sistema operativo possa trovarle.
L'azione finale consiste nel compilare la libreria e assicurarsi di non avere errori di compilazione. Spesso si nota che le associazioni dei metadati prodotti da Objective Sharpie verranno annotate con l'attributo
[Verify]
. Questi attributi indicano che è necessario verificare che Objective Sharpie abbia fatto la cosa corretta confrontando l'associazione con la dichiarazione originale Objective-C (che verrà fornita in un commento sopra la dichiarazione associata). Per altre informazioni sui membri contrassegnati con l'attributo , vedere il collegamento seguente. Dopo aver compilato il progetto, può essere usato da un'applicazione Xamarin.iOS.
Utilizzare la libreria di binding
Il passaggio finale consiste nell'usare la libreria di binding Xamarin.iOS in un'applicazione Xamarin.iOS. Creare un nuovo progetto Xamarin.iOS, aggiungere un riferimento alla libreria di binding e attivare Gigya Swift SDK:
Creare un progetto Xamarin.iOS. È possibile usare l'app a visualizzazione singola dell'app > iOS > come punto di partenza:
Aggiungere un riferimento al progetto di associazione al progetto di destinazione o .dll creato in precedenza. Considerare la libreria di binding come una normale libreria Xamarin.iOS:
Aggiornare il codice sorgente dell'app e aggiungere la logica di inizializzazione al viewController primario, che attiva Gigya SDK
public override void ViewDidLoad() { base.ViewDidLoad(); var proxy = new SwiftFrameworkProxy(); var result = proxy.InitForApiKey("APIKey"); System.Diagnostics.Debug.WriteLine(result); }
Creare un pulsante con un nome btnLogin e aggiungere il gestore di clic del pulsante seguente per attivare un flusso di autenticazione:
private void btnLogin_Tap(object sender, EventArgs e) { _proxy.LoginWithProvider(GigyaSocialProvidersProxy.Instagram, this, (result, error) => { // process your login result here }); }
Eseguire l'app, nell'output di debug dovrebbe essere visualizzata la riga seguente:
Gigya initialized with domain: us1.gigya.com
. Fare clic sul pulsante per attivare il flusso di autenticazione:
Complimenti. È stata creata correttamente un'app Xamarin.iOS e una libreria di binding che usa un framework Swift. L'applicazione precedente verrà eseguita correttamente in iOS 12.2+ perché a partire da questa versione di iOS Apple ha introdotto la stabilità ABI e ogni iOS a partire dalla versione 12.2+ include librerie di runtime Swift, che potrebbero essere usate per eseguire l'applicazione compilata con Swift 5.1+. Se è necessario aggiungere il supporto per le versioni precedenti di iOS, è necessario eseguire alcuni passaggi aggiuntivi:
Per aggiungere il supporto per iOS 12.1 e versioni precedenti, è necessario distribuire dylibs Swift specifici usati per compilare il framework. Usare il pacchetto NuGet Xamarin.iOS.SwiftRuntimeSupport per elaborare e copiare le librerie necessarie con l'IPA. Aggiungere il riferimento NuGet al progetto di destinazione e ricompilare l'applicazione. Non sono necessari altri passaggi, il pacchetto NuGet installerà attività specifiche, eseguite con il processo di compilazione, identificando i dylib Swift necessari e crearne il pacchetto con l'IPA finale.
Per inviare l'app all'App Store che vuoi usare Xcode e l'opzione di distribuzione, che aggiornerà il file IPA e i dylib della cartella SwiftSupport in modo che vengano accettati dall'AppStore:
]. Archiviare l'app. Dal menu Visual Studio per Mac selezionare Compila > archivio per pubblicazione:
Questa azione compila il progetto e lo ottiene all'organizzatore, accessibile da Xcode per la distribuzione.
Interoperabilità distribuita tramite Xcode. Aprire Xcode e passare all'opzione di menu Libreria finestre>:
Selezionare l'archivio creato nel passaggio precedente e fare clic sul pulsante Distribuisci app. Seguire la procedura guidata per caricare l'applicazione nell'AppStore.
Questo passaggio è facoltativo, ma è importante verificare che l'app possa essere eseguita in iOS 12.1 e versioni precedenti e 12.2. È possibile farlo con l'aiuto del framework Test Cloud e UITest. Creare un progetto UITest e un test di interfaccia utente di base, che esegue l'app:
Creare un progetto UITest e configurarlo per l'applicazione Xamarin.iOS:
Suggerimento
Per altre informazioni su come creare un progetto UITest e configurarlo per l'app, vedere il collegamento seguente.
Creare un test di base per eseguire l'app e usare alcune delle funzionalità di Swift SDK. Questo test attiva l'app, tenta di accedere e quindi preme il pulsante Annulla:
[Test] public void HappyPath() { app.WaitForElement(StatusLabel); app.WaitForElement(LoginButton); app.Screenshot("App loaded."); Assert.AreEqual(app.Query(StatusLabel).FirstOrDefault().Text, "Gigya initialized with domain: us1.gigya.com"); app.Tap(LoginButton); app.WaitForElement(GigyaWebView); app.Screenshot("Login activated."); app.Tap(CancelButton); app.WaitForElement(LoginButton); app.Screenshot("Login cancelled."); }
Suggerimento
Per altre informazioni sul framework UITests e Automazione interfaccia utente, vedere il collegamento seguente.
Creare un'app iOS nel Centro app, creare una nuova esecuzione di test con un nuovo dispositivo impostato per eseguire il test:
Suggerimento
Per altre informazioni su AppCenter Test Cloud, vedere il collegamento seguente.
Installare l'interfaccia della riga di comando di AppCenter
npm install -g appcenter-cli
Importante
Assicurarsi di avere installato node v6.3 o versione successiva
Eseguire il test usando il comando seguente. Assicurarsi anche che la riga di comando di appcenter sia attualmente connesso.
appcenter test run uitest --app "Mobile-Customer-Advisory-Team/SwiftBinding.iOS" --devices a7e7cb50 --app-path "Xamarin.SingleView.ipa" --test-series "master" --locale "en_US" --build-dir "Xamarin/Xamarin.SingleView.UITests/bin/Debug/"
Verificare il risultato. Nel portale di AppCenter passare all'esecuzione del test > dell'app>:
Selezionare l'esecuzione del test desiderato e verificare il risultato:
È stata sviluppata un'applicazione Xamarin.iOS di base che usa un framework Swift nativo tramite una libreria di binding Xamarin.iOS. L'esempio fornisce un modo semplicistico per usare il framework selezionato e in un'applicazione reale sarà necessario esporre più API e preparare i metadati per queste API. Lo script per generare metadati semplifica le modifiche future alle API del framework.
Collegamenti correlati
- Xcode
- Visual Studio per Mac
- Objective Sharpie
- Verifica dei metadati sharpie
- Framework di binding Objective-C
- Gigya iOS SDK (framework Swift)
- Stabilità ABI Swift 5.1
- SwiftRuntimeSupport NuGet
- Automazione di test dell'interfaccia utente di Xamarin
- Configurazione uitest di Xamarin.iOS
- AppCenter Test Cloud
- Repository di progetti di esempio