中安拓也のブログ

プログラミングについて書くブログ

自作CordovaプラグインのIonic Nativeを作る

はじめに

以前作ったCordovaプラグイン、cordova-plugin-cache-deleteIonic Nativeを作ります。

Ionic Nativeとは

Ionic NativeとはCordova プラグインのTypeScriptラッパーであり、コールバック関数ベースのCordova プラグインを、PromiseまたはObservableベースに変換する機能を提供します。

cordova-plugin-cache-delete自体は、Ionic Nativeを使わなくてもすでにPromiseでラップ済なので、Promise経由で機能を呼び出すことができるプラグインになっています。 しかし、アンビエント宣言の省略など、他のIonic Nativeを持つCordovaプラグインと平仄を合わせるためにcordova-plugin-cache-deleteについても今回の記事でIonic Nativeを作成して、TypeScriptでラップできるようにします。

環境

今回作成したIonic Nativeは、下記バージョンのIonic(Angular, Cordova)で作成したAndroidアプリ上で動作確認しています。

ionic infoコマンドの実行結果

$ ionic info

Ionic:

   Ionic CLI                     : 6.11.8 (/usr/local/lib/node_modules/@ionic/cli)
   Ionic Framework               : @ionic/angular 5.6.6
   @angular-devkit/build-angular : 0.1102.11
   @angular-devkit/schematics    : 11.2.11
   @angular/cli                  : 11.2.11
   @ionic/angular-toolkit        : 3.1.1

Cordova:

   Cordova CLI       : 10.0.0
   Cordova Platforms : android 9.1.0
   Cordova Plugins   : cordova-plugin-ionic-keyboard 2.2.0, cordova-plugin-ionic-webview 4.2.1, (and 5 other plugins)

Utility:

   cordova-res : not installed
   native-run  : not installed

System:

   ios-deploy : 1.9.2
   ios-sim    : 6.1.2
   NodeJS     : v12.13.1 (/usr/local/bin/node)
   npm        : 6.14.12
   OS         : macOS Catalina
   Xcode      : Xcode 12.4 Build version 12D4e

Ionic Native作成

それでは、ionic-team / ionic-nativeリポジトリのDEVELOPER.mdの手順に従って、カスタムIonic Nativeを作成していきます

Ionic Nativeのテンプレートを作成

Ionic Nativeを作成するにあたって、ベースになるテンプレートから作成していきます。

まず、Ionic NativeのリポジトリをForkします。

f:id:l08084:20210522174457p:plain
Ionic NativeをForkする

その後、Forkしたリポジトリをクローンして、クローンしたIonic Nativeのルートディレクトリに移動します。

$ git clone https://github.com/l08084/ionic-native.git
$ cd ionic-native

テンプレートの作成に使用するため、なければgulp.jsをインストールします。

$ gulp -v
bash: gulp: command not found
$ sudo npm install -g gulp
$ gulp -v
CLI version: 2.3.0
Local version: Unknown

gulpのインストールが完了したら、クローンしたIonic Nativeのルート上で、npm iして環境を整えます。

その後、テンプレートを作成するコマンドである、gulp plugin:create -n CacheDeleteを実行します。

CacheDeleteの部分は、今回Ionic Nativeを作成したいCordovaプラグインの名前です。

$ pwd
/Users/takuya/fork/ionic-native
$ npm i
$ gulp plugin:create -n CacheDelete

gulp plugin:create -n PluginNameコマンドを実行すると、Ionic Nativeの./gulpfile.jsのタスクが呼び出されて、ディレクトリ(src/@ionic-native/plugins/plugin-name/)とindex.tsが新規作成されます。

f:id:l08084:20210522173311p:plain
./gulpfile.js

新規作成されたindex.tsの内容は以下の通りになります。

src/@ionic-native/plugins/cache-delete/index.ts

/**
 * This is a template for new plugin wrappers
 *
 * TODO:
 * - Add/Change information below
 * - Document usage (importing, executing main functionality)
 * - Remove any imports that you are not using
 * - Remove all the comments included in this template, EXCEPT the @Plugin wrapper docs and any other docs you added
 * - Remove this note
 *
 */
import { Injectable } from '@angular/core';
import { Plugin, Cordova, CordovaProperty, CordovaInstance, InstanceProperty, IonicNativePlugin } from '@ionic-native/core';
import { Observable } from 'rxjs';

/**
 * @name Cache Delete
 * @description
 * This plugin does something
 *
 * @usage
 * ```typescript
 * import { CacheDelete } from '@ionic-native/cache-delete';
 *
 *
 * constructor(private cacheDelete: CacheDelete) { }
 *
 * ...
 *
 *
 * this.cacheDelete.functionName('Hello', 123)
 *   .then((res: any) => console.log(res))
 *   .catch((error: any) => console.error(error));
 *
 * ```
 */
@Plugin({
  pluginName: 'CacheDelete',
  plugin: '', // npm package name, example: cordova-plugin-camera
  pluginRef: '', // the variable reference to call the plugin, example: navigator.geolocation
  repo: '', // the github repository URL for the plugin
  install: '', // OPTIONAL install command, in case the plugin requires variables
  installVariables: [], // OPTIONAL the plugin requires variables
  platforms: [] // Array of platforms supported, example: ['Android', 'iOS']
})
@Injectable()
export class CacheDelete extends IonicNativePlugin {

  /**
   * This function does something
   * @param arg1 {string} Some param to configure something
   * @param arg2 {number} Another param to configure something
   * @return {Promise<any>} Returns a promise that resolves when something happens
   */
  @Cordova()
  functionName(arg1: string, arg2: number): Promise<any> {
    return; // We add return; here to avoid any IDE / Compiler errors
  }

}

これでテンプレートの作成は完了です。

プラグインラッパーの作成

作成されたindex.tsをソースコードに記載されているコメント通りに修正していくと下記のようになります。

import { Injectable } from '@angular/core';
import { Plugin, Cordova, IonicNativePlugin } from '@ionic-native/core';

/**
 * @name Cache Delete
 * @description
 * Cordova plugin to delete Webview cache
 *
 * @usage
 * ```typescript
 * import { CacheDelete } from '@ionic-native/cache-delete';
 *
 *
 * constructor(private cacheDelete: CacheDelete) { }
 *
 * ...
 *
 *
 * this.cacheDelete.deleteCache()
 *   .then((res: any) => console.log(res))
 *   .catch((error: any) => console.error(error));
 *
 * ```
 */
@Plugin({
  pluginName: 'CacheDelete',
  plugin: 'cordova-plugin-cache-delete',
  pluginRef: 'CacheDelete',
  repo: 'https://github.com/l08084/cordova-plugin-cache-delete',
  platforms: ['Android']
})
@Injectable()
export class CacheDelete extends IonicNativePlugin {

  /**
   * delete a cordova webview cache.
   *
   * @returns {Promise<any>} Returns a Promise
   */
  @Cordova({ sync: true })
  deleteCache(): Promise<any> {
    return;
  }

}

Cordovaデコレーターにsync: trueをセットしているのは(@Cordova({ sync: true }))、Promiseでラップせずに値をそのまま返す必要があるためです。(cordova-plugin-cache-deleteの方ですでに値をPromiseでラップ済のため、Ionic Nativeの方でPromseでラップする必要がない)

Cordovaデコレーターの引数の詳細な内容については、ionic-team / ionic-nativeリポジトリのDEVELOPER.mdに詳しく載っています。

これでIonic Nativeの作成は完了です。

動作確認

作成したIonic Native経由でCordovaプラグインcordova-plugin-cache-deleteを呼び出すことができるかIonicアプリで確認します。

まず、npm run lintコマンドでコーディング規約に反したコードがないか確認します。

$ npm run lint

Lintエラーが出力されないのを確認したら、npm run buildコマンドでビルドを実施します。

$ npm run build

ビルドが成功すると、このようにdistディレクトリが作成されます。

f:id:l08084:20210523163611p:plain
distディレクトリが作成される

作成されたdistディレクトリの構造は以下のようになっています。

dist/@ionic-native/plugins/cache-delete
├── index.d.ts
├── index.js
└── ngx
    ├── bundle.js
    ├── index.d.ts
    ├── index.js
    └── index.metadata.json

続いて、作成したdistディレクトリ配下のcache-deleteディレクトリを、テストしたいIonicアプリのnode_modules/@ionic-nativeのディレクトリ配下に移動します。

f:id:l08084:20210523171136p:plain

Ionicアプリから今回作成したIonic Nativeを呼び出します。

Ionic Nativeを呼び出すために、コードを下記のように修正します。

src/app/app.module.ts

import { CacheDelete } from '@ionic-native/cache-delete/ngx';

// ...省略

@NgModule({
  // ...省略
  providers: [
    // ...省略
    CacheDelete,
    // ...省略
  ],
  // ...省略
})
export class AppModule {}

src/app/tab1/tab1.page.ts

import { Component } from '@angular/core';
import { Platform } from '@ionic/angular';
import { CacheDelete } from '@ionic-native/cache-delete/ngx';

@Component({
  selector: 'app-tab1',
  templateUrl: 'tab1.page.html',
  styleUrls: ['tab1.page.scss'],
})
export class Tab1Page {
  constructor(private platform: Platform, private cacheDelete: CacheDelete) {}

  public ngOnInit(): void {
    this.platform.ready().then(() => {
      if (this.platform.is('android')) {
        // delete cache
        this.cacheDelete
          .deleteCache()
          .then(() => console.log('delete cache success!!'))
          .catch((error) => console.error(error));
      }
    });
  }

  public delete(): void {
    this.cacheDelete
      .deleteCache()
      .then(() => console.log('delete cache success!!'))
      .catch((error) => console.error(error));
  }
}

上記のIonicアプリをビルドしてシミュレーターで動かすと、今回作成したIonic Native経由でCordovaプラグインの呼び出せることを確認できます。

参考サイト

Ionic Native - Ionic Native

【ionic】Ionic native pluginの作成|ブログ|West Wind Corporation

Ionic Native Pluginを自作する - Qiita

ionic-native/DEVELOPER.md at master · ionic-team/ionic-native · GitHub

Create Ionic TypeScript wrapper from my Cordova Custom plugins - Stack Overflow

GitHub - ionic-team/ionic-native: Native features for mobile apps built with Cordova/PhoneGap and open web technologies. Complete with TypeScript support. The successor to ngCordova. Pairs exquisitely with a nice bottle of Ionic Framework.

Ionic 4 Cordova Custom Plugin using Ionic-Native - Ionic Native - Ionic Forum