{"id":3552,"date":"2021-08-06T15:45:58","date_gmt":"2021-08-06T15:45:58","guid":{"rendered":"https:\/\/cloudsurfers.it\/?p=3552"},"modified":"2021-08-06T15:46:02","modified_gmt":"2021-08-06T15:46:02","slug":"creare-un-plugin-capacitor-3","status":"publish","type":"post","link":"https:\/\/cloudsurfers.it\/index.php\/creare-un-plugin-capacitor-3\/","title":{"rendered":"Creare un plugin Capacitor 3"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1500\" height=\"844\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Capacitors_7189597135-edited.jpg\" alt=\"\" class=\"wp-image-3559\" srcset=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Capacitors_7189597135-edited.jpg 1500w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Capacitors_7189597135-edited-300x169.jpg 300w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Capacitors_7189597135-edited-1024x576.jpg 1024w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Capacitors_7189597135-edited-768x432.jpg 768w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Capacitors_7189597135-edited-600x338.jpg 600w\" sizes=\"auto, (max-width: 1500px) 100vw, 1500px\" \/><\/figure>\n\n\n\n<p>In questa guida scopriremo, insieme ad una piccola implementazione di esempio, tutte le fasi della creazione di un plugin <strong>Capacitor 3<\/strong>, e come utilizzarlo successivamente all&#8217;interno di un progetto di <strong>Ionic 5<\/strong> di esempio.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Premessa<\/h3>\n\n\n\n<p>Il plugin generato \u00e8 compatibile con <strong>Android<\/strong>, <strong>iOS <\/strong>e anche <strong>browser web<\/strong> come WebApp. In questa guida per\u00f2 effettueremo solo l&#8217;implementazione di un metodo nativo Android scritto in <strong>Java<\/strong>, per testarlo successivamente all&#8217;interno di un progetto Ionic.<\/p>\n\n\n\n<p>Nel nostro caso utilizziamo una macchina con sistema operativo Windows ma l&#8217;intera procedura pu\u00f2 essere replicata anche su sistema operativo MacOS o su una distribuzione Linux. Tutti gli strumenti utilizzati sono infatti multipiattaforma.<\/p>\n\n\n\n<p>Una piccola precisazione, come per la compilazione iOS \u00e8 necessario MacOS, anche per la compilazione di un plugin Capacitor iOS \u00e8 necessario XCode e quindi MacOS.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Requisiti<\/h3>\n\n\n\n<p>Sulla nostra macchina avremo bisogno di:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/nodejs.org\/it\/\" target=\"_blank\" rel=\"noreferrer noopener\">Node LTS<\/a> (14.17.4 al momento della scrittura di questo articolo);<\/li><li><a href=\"https:\/\/code.visualstudio.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Visual Studio Code<\/a>;<\/li><li><a href=\"https:\/\/developer.android.com\/studio\" target=\"_blank\" rel=\"noreferrer noopener\">Android Studio<\/a> con gli strumenti SDK installati<\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Iniziamo<\/h3>\n\n\n\n<p>Creiamo una nuova cartella di lavoro e posizioniamoci al suo interno con un terminale <em>CMD <\/em>o <strong>PowerShell <\/strong>e lanciamo il comando di inizializzazione di un nuovo plugin:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm init @capacitor\/plugin<\/code><\/pre>\n\n\n\n<p>Durante l&#8217;esecuzione della procedura verranno richiesti alcuni parametri di configurazione:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Il nome del pacchetto <em>NPM <\/em>che avr\u00e0 il plugin, sar\u00e0 quello utilizzato anche per un eventuale pubblicazione;<\/li><li>La cartella che verr\u00e0 utilizzata in fase di sviluppo, di default quella in cui abbiamo avviato il terminale;<\/li><li>L&#8217;identificativo univoco del pacchetto, nel nostro esempio <em>com.cloudsurfers.plugins.examplecapacitor<\/em>;<\/li><li>Il nome della classe principale, <strong>Example <\/strong>nel nostro caso;<\/li><li>L&#8217;URL del repository, che pu\u00f2 essere quella di GitHub del progetto;<\/li><li>L&#8217;autore, anche opzionale;<\/li><li>La licenza del plugin, per esempio licenza MIT;<\/li><li>Infine, una breve descrizione del progetto.<\/li><\/ul>\n\n\n\n<p>Apriamo quindi la cartella principale del progetto appena creata con <strong>VSCODE <\/strong>e da terminale, sempre dalla cartella principale, lanciamo il comando:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install<\/code><\/pre>\n\n\n\n<p>per scaricare tutti i pacchetti necessari.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Implementazione del nuovo metodo<\/h3>\n\n\n\n<p>Il progetto generato in automatico con il comando di <em>Init <\/em>ci propone gi\u00e0 un esempio di implementazione di un metodo chiamato <strong>echo<\/strong>, disponibile sia come implementazione <em>Web<\/em>, <em>iOS <\/em>ed <em>Android<\/em>. La sua definizione si trova all&#8217;interno del file <em>TypeScript <\/em><strong>definition.ts<\/strong>, all&#8217;interno della cartella <strong>src<\/strong>.<\/p>\n\n\n\n<p>Il file si presenta in questo modo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export interface ExamplePlugin {\n  echo(options: { value: string }): Promise&lt;{ value: string }&gt;;\n}\n<\/code><\/pre>\n\n\n\n<p>Andiamo ad aggiungere la definizione nel nostro nuovo metodo, che chiamiamo <strong>getCarInfo <\/strong>e di due nuove interfacce di supporto <strong>CarInfoOptions <\/strong>e <strong>CarModelInfo<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export interface ExamplePlugin {\n  echo(options: { value: string }): Promise&lt;{ value: string }&gt;;\n  getCarInfo(options: CarInfoOptions): Promise&lt;CarModelInfo&#91;]&gt;;\n}\n\nexport interface CarInfoOptions {\n  manufacturer: string\n}\n\nexport interface CarModelInfo {\n  name: string,\n  engine: string\n}\n<\/code><\/pre>\n\n\n\n<p>Il funzionamento sar\u00e0 molto semplice, facendo una chiamata al metodo <strong>getCarInfo<\/strong>, passando come argomento delle opzioni contenenti ad esempio il nome di una casa automobilistica (<em>&#8220;FIAT&#8221;<\/em>), il metodo ritorner\u00e0 l&#8217;elenco di modelli di auto di quella casa automobilistica con alcune informazioni come il nome del modello ed il motore.<\/p>\n\n\n\n<p>Questo esempio, un po&#8217; forzato, non necessita dell&#8217;accesso al codice nativo del sistema (<em>Android <\/em>o <em>iOS<\/em>) per portare a termine il risultato, ma ci aiuta a capire come funzionano e come viene sfruttato il linguaggio nativo all&#8217;interno dei plugin <strong>Capacitor <\/strong>e successivamente poter effettuare implementazioni pi\u00f9 avanzate che devono necessariamente sfruttare componenti specifici del sistema su cui vengono eseguiti.<\/p>\n\n\n\n<p>Detto questo, l&#8217;implementazione <em>Web<\/em>, quindi <strong>Browser Web<\/strong>, si trova all&#8217;interno del file <em>TypeScript <\/em><strong>web.ts<\/strong>, sempre all&#8217;interno della cartella <strong>src<\/strong>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { WebPlugin } from '@capacitor\/core';\n\nimport type { \n  ExamplePlugin,\n  CarInfoOptions,\n  CarModelInfo\n} from '.\/definitions';\n\nexport class ExampleWeb extends WebPlugin implements ExamplePlugin {\n  async echo(options: { value: string }): Promise&lt;{ value: string }&gt; {\n    console.log('ECHO', options);\n    return options;\n  }\n\n  async getCarInfo(options: CarInfoOptions): Promise&lt;CarModelInfo&#91;]&gt; {\n  console.log(options);\n    throw Error(\"Implementazione Web non presente!\");\n  }\n}\n<\/code><\/pre>\n\n\n\n<p>Nel nostro caso, visto che andremo ad effettuare solo l&#8217;implementazione <em>Android<\/em>, facciamo in modo che, nell&#8217;implementazione <em>Web <\/em>sopra, ritorni un errore &#8220;<em>Implementazione Web non presente!<\/em>&#8221; quando il metodo viene invocato.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Implementazione Android<\/h3>\n\n\n\n<p>Utilizzando <strong>Android Studio<\/strong>, apriamo la cartella <strong>android <\/strong>presente all&#8217;interno del progetto del plugin.<\/p>\n\n\n\n<p>Apriamo il file <strong>ExamplePlugin.java<\/strong> (nel nostro caso si chiama cos\u00ec per aver scelto <em>Example <\/em>come classe principale in fase di configurazione) ed aggiungiamo anche qui il metodo <strong>getCarInfo<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.cloudsurfers.plugins.examplecapacitor;\n\nimport com.getcapacitor.JSArray;\nimport com.getcapacitor.JSObject;\nimport com.getcapacitor.Plugin;\nimport com.getcapacitor.PluginCall;\nimport com.getcapacitor.PluginMethod;\nimport com.getcapacitor.annotation.CapacitorPlugin;\n\n@CapacitorPlugin(name = \"Example\")\npublic class ExamplePlugin extends Plugin {\n\n    private Example implementation = new Example();\n\n    @PluginMethod\n    public void echo(PluginCall call) {\n        String value = call.getString(\"value\");\n\n        JSObject ret = new JSObject();\n        ret.put(\"value\", implementation.echo(value));\n        call.resolve(ret);\n    }\n\n    @PluginMethod\n    public void getCarInfo(PluginCall call) {\n        String manufacturer = call.getString(\"manufacturer\");\n\n        JSObject ret = new JSObject();\n        JSArray arr = new JSArray();\n\n        if(manufacturer.equals(\"FIAT\")){\n            arr.put(new JSObject()\n                .put(\"name\", \"PUNTO\")\n                .put(\"engine\", \"1.0 BENZINA\"));\n            arr.put(new JSObject()\n                .put(\"name\", \"PUNTO\")\n                .put(\"engine\", \"1.3 DIESEL\"));\n            arr.put(new JSObject()\n                .put(\"name\", \"TIPO\")\n                .put(\"engine\", \"1.3 DIESEL\"));\n            arr.put(new JSObject()\n                .put(\"name\", \"CROMA\")\n                .put(\"engine\", \"2.0 DIESEL\"));\n        } else if (manufacturer.equals(\"SEAT\")){\n            arr.put(new JSObject()\n                .put(\"name\", \"IBIZA\")\n                .put(\"engine\", \"1.0 BENZINA\"));\n            arr.put(new JSObject()\n                .put(\"name\", \"LEON\")\n                .put(\"engine\", \"2.0 DIESEL\"));\n        }\n\n        ret.put(\"models\", arr);\n        call.resolve(ret);\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>Come si pu\u00f2 vedere, utilizzando l&#8217;oggetto <strong>PluginCall <\/strong>riusciamo ad ottenere gli eventuali argomenti passati come parametro al metodo, ed eventualmente, una volta eseguita la logica, risolvere con un output o rigettare la chiamata con un errore, se serve.<\/p>\n\n\n\n<p>L&#8217;output deve essere di tipo <strong>JSObject<\/strong>. In questo caso l&#8217;output sar\u00e0 un <em>JSON <\/em>composto da un array &#8220;<strong>models<\/strong>&#8221; (<strong>JSArray<\/strong>) con a sua volta al suo interno uno o pi\u00f9 <strong>JSObject <\/strong>con due propriet\u00e0: <strong>name <\/strong>ed <strong>engine<\/strong>.<\/p>\n\n\n\n<p>A questo punto l&#8217;implementazione <em>Android <\/em>\u00e8 terminata, si prosegue cos\u00ec con la compilazione e successivo test locale del plugin.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Compilazione<\/h3>\n\n\n\n<p>Dalla cartella principale del progetto del plugin, lanciamo da terminale:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm run build<\/code><\/pre>\n\n\n\n<p>per compilare il plugin e permetterne l&#8217;utilizzo all&#8217;interno di un progetto <strong>Ionic<\/strong>.<\/p>\n\n\n\n<p>Al termine della procedura il plugin \u00e8 gi\u00e0 pronto per essere testato ed eventualmente pubblicato su <em>NPM<\/em>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Utilizzare il plugin in un progetto Ionic<\/h3>\n\n\n\n<p>Creiamo un nuovo progetto <strong>Ionic <\/strong>(<strong>Angular <\/strong>+ <strong>Capacitor<\/strong>) con il comando:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ionic start<\/code><\/pre>\n\n\n\n<p>seguiamo la procedura guidata, nel mio caso ho scelto un template <strong>app tab<\/strong>.<\/p>\n\n\n\n<p>Proseguiamo lanciando:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install\nnpm install @capacitor\/android<\/code><\/pre>\n\n\n\n<p>per l&#8217;installazione di tutti i pacchetti necessari e successivamente:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm cap init\nnpm cap add android<\/code><\/pre>\n\n\n\n<p>per inizializzare <em>Capacitor <\/em>e aggiungere la piattaforma <em>Android <\/em>al progetto.<\/p>\n\n\n\n<p>A questo punto il nostro progetto <em>Ionic <\/em>di esempio \u00e8 pronto ed \u00e8 gi\u00e0 compilabile ed eseguibile su un dispositivo Android, che sia un dispositivo fisico o un emulatore su <em>Android Studio<\/em>.<\/p>\n\n\n\n<p>Tramite <em>NPM <\/em>installiamo ora il plugin creato in precedenza dalla sua cartella locale di sviluppo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install \"cartella_principale_locale_plugin\"<\/code><\/pre>\n\n\n\n<p>Avendo scelto il template <strong>Angular Tab<\/strong> la prima pagina che viene caricata dall&#8217;app \u00e8 la <em>tab 1<\/em>, quindi andiamo ad aprire il file <strong>tab1.page.ts<\/strong> ed importiamo il plugin e l&#8217;interfaccia per le opzioni come segue:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { CarInfoOptions, Example } from 'cloudsurfers-example-capacitor-plugin';<\/code><\/pre>\n\n\n\n<p>All&#8217;interno dell&#8217;evento <strong>ngOnInit <\/strong>richiamiamo il nostro plugin:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ngOnInit(){\n    console.log(Example.getCarInfo({\n      manufacturer: \"FIAT\"\n    } as CarInfoOptions));\n  }\n<\/code><\/pre>\n\n\n\n<p>Ora compiliamo, sincronizziamo ed aggiorniamo i dati per il progetto <em>Android<\/em>. Lanciamo successivamente sull&#8217;emulatore o su un dispositivo fisico.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ionic build\nnpx cap update android\nnpx cap sync android\nnpx cap open android<\/code><\/pre>\n\n\n\n<p>All&#8217;avvio dell&#8217;app il plugin stamper\u00e0 all&#8217;interno della console <em>Javascript <\/em>l&#8217;oggetto contenente tutti i modelli &#8220;<em>FIAT<\/em>&#8221; come impostato all&#8217;interno del parametro del nostro metodo <strong>getCarInfo<\/strong>:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Screenshot_1628238161-473x1024.png\" alt=\"\" class=\"wp-image-3555\" width=\"256\" height=\"554\" srcset=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Screenshot_1628238161-473x1024.png 473w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Screenshot_1628238161-138x300.png 138w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Screenshot_1628238161-768x1664.png 768w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Screenshot_1628238161-709x1536.png 709w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Screenshot_1628238161-945x2048.png 945w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Screenshot_1628238161-600x1300.png 600w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Screenshot_1628238161.png 1080w\" sizes=\"auto, (max-width: 256px) 100vw, 256px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"628\" height=\"257\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Cattura_Console.png\" alt=\"\" class=\"wp-image-3556\" srcset=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Cattura_Console.png 628w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Cattura_Console-300x123.png 300w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/Cattura_Console-600x246.png 600w\" sizes=\"auto, (max-width: 628px) 100vw, 628px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Conclusione<\/h3>\n\n\n\n<p>Questo \u00e8 un esempio abbastanza semplice di come creare un plugin <strong>Capacitor 3<\/strong>. Partendo da questo per\u00f2 \u00e8 possibile sperimentare qualcosa di pi\u00f9 avanzato ed interagire con componenti di sistema, per esempio interfacce <strong>Wifi <\/strong>o <strong>Camera<\/strong> e cucire un plugin ad-hoc per le nostre esigenze.<\/p>\n\n\n\n<p><a href=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/08\/cloudsurfers-example-capacitor-plugin.zip\" target=\"_blank\" rel=\"noreferrer noopener\">Qui <\/a>trovare l&#8217;archivio compresso del progetto plugin di esempio creato sopra.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Link Utili<\/h3>\n\n\n\n<p><a href=\"https:\/\/capacitorjs.com\/docs\/plugins\/creating-plugins\">https:\/\/capacitorjs.com\/docs\/plugins\/creating-plugins<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/ionic-team\/create-capacitor-plugin\">https:\/\/github.com\/ionic-team\/create-capacitor-plugin<\/a><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In questa guida scopriremo, insieme ad una piccola implementazione di esempio, tutte le fasi della creazione di un plugin Capacitor 3, e come utilizzarlo successivamente all&#8217;interno di un progetto di Ionic 5 di esempio.<\/p>\n","protected":false},"author":3,"featured_media":3559,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"wds_primary_category":0,"footnotes":""},"categories":[152,109,36,153],"tags":[156,96,155,154,157,159,110,158],"class_list":["post-3552","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-angular","category-guide","category-ionic","tag-android","tag-app","tag-capacitor","tag-ionic","tag-ios","tag-plugin","tag-tutorial","tag-webapp"],"_links":{"self":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/posts\/3552","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/comments?post=3552"}],"version-history":[{"count":0,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/posts\/3552\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/media\/3559"}],"wp:attachment":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/media?parent=3552"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/categories?post=3552"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/tags?post=3552"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}