ionic-native從零建立angular自定義插件

前言

最近在開發angular工程的自定義插件api以實現cordova插件的調用時,發現網上的教程幾乎搜不到angular關於自定義插件api開發的文章,而後發現能夠參照@ionic-native的插件代碼結構整出來,因而就模仿着弄,搞了個簡單的腳手架,而後折騰了一個週末總算弄出來了,過程仍是有曲有折,故發文記錄分享javascript

1 介紹

本文將細緻講解cordova插件的建立、編寫、發佈到自定義@ionic-native/plugin的建立、發佈過程,以及自定義ionic-native的腳手架開發、發佈過程,還有angular項目中如何經過調用自定義@ionic-native/plugin來達到調取cordova插件的具體流程。html

2 cordova插件開發

2.1 建立Cordova項目

建立以前確保安裝Cordovajava

cordova create CordovaProject io.cordova.hellocordova CordovaApp
CordovaProject               是建立應用程序的目錄名稱。
io.cordova.hellocordova      是默認的反向域值。 若是可能,您應該使用您本身的域值。
CordovaApp                   是您應用的標題。

本人在jobProject下建立 CordovaProjectnode

$ cordova create CordovaProject com.ths.ll 思路提示框插件

2.2 安裝依賴plugman

plugman是用於安裝和卸載用於Apache Cordova項目的插件的命令行工具。
進入CordovaProject項目目錄,安裝plugmanlinux

$ cd ./CordovaProjectPlugins
$ npm install -g plugman

2.3 建立插件

2.3.1建立一個最簡單的Toast插件

plugman create --name [插件名] --plugin_id [插件id] --plugin_version [插件版本]

爲了方便管理,將插件建立在 Cordova 項目目錄下的 plugins 文件夾下android

$ cd plugins
$ plugman create --name ThsToast --plugin_id cordova-plugin-ths-toast --plugin_version 1.0.0


接着手動將ThsToast目錄重命名爲上述plugin_id的值cordova-plugin-ths-toast,這裏以及上面的ths表示的是公司的統一插件開發前綴,一般是英文字符串ios

進入插件目錄,添加插件支持的平臺環境git

$ cd cordova-plugin-ths-toast
$ plugman platform add --platform_name android
$ plugman platform add --platform_name ios

添加以後將在cordova-plugin-ths-toast目錄下產生android和ios兩個目錄,此處只定義android環境的ThsToast,
生成的文件內容如圖所示github


注意:起名不要和安卓原生方法衝突了,好比這裏ThsToast若是改爲Toast,就會和android.widget.Toast中的Toast類重名,致使構建報錯typescript


2.3.2 插件配置

添加完平臺後,cordova-plugin-ths-toast 目錄下的 plugin.xml 文件將添加以下內容

修改 plugin.xml 文件內容以下

<?xml version='1.0' encoding='utf-8'?>
<plugin id="cordova-plugin-ths-toast" version="1.0.0" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
    <name>Toast</name>
    <js-module name="ThsToast" src="www/ThsToast.js">
        <!-- target修改 -->
        <clobbers target="ThsToast" />
    </js-module>

    <platform name="android">
        <config-file parent="/*" target="res/xml/config.xml">
            <feature name="ThsToast">
            <!-- param value修改 -->
                <param name="android-package" value="org.apache.cordova.thstoast.ThsToast" />
            </feature>
        </config-file>
        <config-file parent="/*" target="AndroidManifest.xml" />
        <!-- target-dir修改 -->
        <source-file src="src/android/ThsToast.java" target-dir="src/org/apache/cordova/thstoast" />
    </platform>

    <platform name="ios">
        <config-file parent="/*" target="config.xml">
            <feature name="ThsToast">
                <param name="ios-package" value="ThsToast" />
            </feature>
        </config-file>
        <source-file src="src/ios/ThsToast.m" />
    </platform>
</plugin>

修改www/ThsToast.js,順帶提一下其中exec方法就是調用cordova插件的原始方法,該方法傳的'ThsToast','show'和[arg0],success,error參數對應的分別是android/ThsToast.java中的class類名,action和args,callbackContext.success,callbackContext.error



修改 android/ThsToast.java 文件,

2.3.3 初始化插件

npm init

提示的時候name輸入插件id,其他根據提示填寫,不清楚就直接按回車到結束,將建立一個 package.json 文件

{
  "name": "cordova-plugin-ths-toast",
  "version": "1.0.0",
  "description": "show toast",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/qtpalmtop/cordova-plugin-ths-toast.git"
  },
  "author": "lilin",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/qtpalmtop/cordova-plugin-ths-toast/issues"
  },
  "homepage": "https://github.com/qtpalmtop/cordova-plugin-ths-toast#readme"
}

接着修改package.json,keywords關鍵字配置是爲了在Cordova Plugin Search中顯示插件,engines配置是插件可能會列出多個發行版的依賴關係,以便在Cordova CLI選擇要從npm獲取的插件版本時向其提供指導,旨在最終替換plugin.xml中的engine元素。
詳細內容請參考cordova建立插件

{
  "name": "cordova-plugin-ths-toast",
  "version": "1.0.0",
  "description": "show toast",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/qtpalmtop/cordova-plugin-ths-toast.git"
  },
  "author": "lilin",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/qtpalmtop/cordova-plugin-ths-toast/issues"
  },
  "homepage": "https://github.com/qtpalmtop/cordova-plugin-ths-toast#readme",
  "keywords": [
    "ecosystem:cordova",
    "cordova-android",
    "cordova-ios"
  ],
  "engines": {
    "cordovaDependencies": {
      "2.0.0": {
        "cordova-android": ">=3.6.0"
      },
      "4.0.0": {
        "cordova-android": ">=3.6.0",
        "cordova-windows": ">=4.4.0"
      },
      "6.0.0": {
        "cordova": ">100"
      }
    },
    "node": ">=6.0.0"
  }
}

2.3.4 發佈插件

發佈後就能夠正常的經過cordova plugin add cordova-plugin-ths-toast在項目中經過ThsToast.show()使用,可是要在angular項目中使用還須要咱們開發自定義插件api,下面咱們開始ionic-native的api模塊開發

cd cordova-plugin-ths-toast
npm login
npm publish

3 建立ionic-native插件

使用過@ionic-native庫的同窗確定都知道,@ionic-native庫能夠直接導入angular項目中,使用起來也很是方便,只須要在app.module.ts中導入api

// app.module.ts
import { SplashScreen } from '@ionic-native/splash-screen/ngx';

@NgModule({
...,
providers: [
    ...,
    SplashScreen
  ]
})

而後在使用的模塊中導入sdk就能直接調用起cordova插件功能

// app.component.ts
import { SplashScreen } from '@ionic-native/splash-screen/ngx';

export class AppComponent {
    constructor(
        private splashScreen: SplashScreen
    ) {
        this.splashScreen.hide();
    }
}

那麼要如何才能建立出@ionic-native庫同樣的插件呢?

3.1 @ionic-native插件代碼拆解

首先咱們安裝下@ionic-native/splash-screen

npm install @ionic-native/splash-screen

能夠看到插件結構以下


index.js

分析:__extends函數功能能夠理解爲是繼承再也不詳細闡述,左邊的參數對象會繼承右邊的對象,SplashScreenOriginal裏新建了個函數SplashScreenOriginal,__extends(SplashScreenOriginal, _super)讓該對象繼承自IonicNativePlugin,這樣就具有IonicNativePlugin的一些功能,最後導出SplashScreenOriginal的實例SplashScreen供咱們調用

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
import { IonicNativePlugin, cordova } from '@ionic-native/core';
var SplashScreenOriginal = /** @class */ (function (_super) {
    __extends(SplashScreenOriginal, _super);
    function SplashScreenOriginal() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    SplashScreenOriginal.prototype.show = function () { return cordova(this, "show", { "sync": true }, arguments); };
    SplashScreenOriginal.prototype.hide = function () { return cordova(this, "hide", { "sync": true }, arguments); };
    SplashScreenOriginal.pluginName = "SplashScreen";
    SplashScreenOriginal.plugin = "cordova-plugin-splashscreen";
    SplashScreenOriginal.pluginRef = "navigator.splashscreen";
    SplashScreenOriginal.repo = "https://github.com/apache/cordova-plugin-splashscreen";
    SplashScreenOriginal.platforms = ["Amazon Fire OS", "Android", "iOS", "Windows"];
    return SplashScreenOriginal;
}(IonicNativePlugin));
var SplashScreen = new SplashScreenOriginal();
export { SplashScreen };

index.d.ts 規定了對象屬性和方法

import { IonicNativePlugin } from '@ionic-native/core';
/**
 * @name Splash Screen
 * @description This plugin displays and hides a splash screen during application launch. The methods below allows showing and hiding the splashscreen after the app has loaded.
 * @usage
 * ```typescript
 * import { SplashScreen } from '@ionic-native/splash-screen/ngx';
 *
 * constructor(private splashScreen: SplashScreen) { }
 *
 * ...
 *
 * this.splashScreen.show();
 *
 * this.splashScreen.hide();
 * ```
 */
export declare class SplashScreenOriginal extends IonicNativePlugin {
    /**
     * Shows the splashscreen
     */
    show(): void;
    /**
     * Hides the splashscreen
     */
    hide(): void;
}

export declare const SplashScreen: SplashScreenOriginal;

上面的代碼導出了一個能調用插件的通用實例,可是要在angular中使用,就得看看ngx的代碼

ngx/index.js
分析:對index.js而言多了__decorate方法,在調用該方法後實例上多了__annotations__隱式屬性,該屬性讓實例以Injectable的方式注入angular中得以調用,能夠理解爲加了個

@Injectable({
    providedIn: "root"
})

調用__decorate前

調用__decorate後

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Injectable } from '@angular/core';
import { IonicNativePlugin, cordova } from '@ionic-native/core';
var SplashScreen = /** @class */ (function (_super) {
    __extends(SplashScreen, _super);
    function SplashScreen() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    SplashScreen.prototype.show = function () { return cordova(this, "show", { "sync": true }, arguments); };
    SplashScreen.prototype.hide = function () { return cordova(this, "hide", { "sync": true }, arguments); };
    SplashScreen.pluginName = "SplashScreen";
    SplashScreen.plugin = "cordova-plugin-splashscreen";
    SplashScreen.pluginRef = "navigator.splashscreen";
    SplashScreen.repo = "https://github.com/apache/cordova-plugin-splashscreen";
    SplashScreen.platforms = ["Amazon Fire OS", "Android", "iOS", "Windows"];
    SplashScreen = __decorate([
        Injectable()
    ], SplashScreen);
    return SplashScreen;
}(IonicNativePlugin));
export { SplashScreen };

ngx/index.d.ts 類型規定和index.d.ts區別不大

import { IonicNativePlugin } from '@ionic-native/core';
/**
 * @name Splash Screen
 * @description This plugin displays and hides a splash screen during application launch. The methods below allows showing and hiding the splashscreen after the app has loaded.
 * @usage
 * ```typescript
 * import { SplashScreen } from '@ionic-native/splash-screen/ngx';
 *
 * constructor(private splashScreen: SplashScreen) { }
 *
 * ...
 *
 * this.splashScreen.show();
 *
 * this.splashScreen.hide();
 * ```
 */
export declare class SplashScreen extends IonicNativePlugin {
    /**
     * Shows the splashscreen
     */
    show(): void;
    /**
     * Hide the splashscreen
     */
    hide(): void;
}

package.json 咱們須要用到的屬性有author做者、dependencies依賴、description插件描述、license、module模塊入口、name插件名稱、peerDependencies同級依賴、repository插件倉庫地址、typings類型規定、version插件版本號

{
  "_args": [
    [
      "@ionic-native/splash-screen@5.9.0",
      "/Users/linli/jobProjects/ionic-angular-demo"
    ]
  ],
  "_from": "@ionic-native/splash-screen@5.9.0",
  "_id": "@ionic-native/splash-screen@5.9.0",
  "_inBundle": false,
  "_integrity": "sha512-6IhAEtVBf8lE7HdLgs+GLm83z9ukfdSwbKS9oMciJe8dpXTY3J2B2Fy8HgXpo88phccHXny1acEpFndns3oEkA==",
  "_location": "/@ionic-native/splash-screen",
  "_phantomChildren": {},
  "_requested": {
    "type": "version",
    "registry": true,
    "raw": "@ionic-native/splash-screen@5.9.0",
    "name": "@ionic-native/splash-screen",
    "escapedName": "@ionic-native%2fsplash-screen",
    "scope": "@ionic-native",
    "rawSpec": "5.9.0",
    "saveSpec": null,
    "fetchSpec": "5.9.0"
  },
  "_requiredBy": [
    "/"
  ],
  "_resolved": "https://registry.npmjs.org/@ionic-native/splash-screen/-/splash-screen-5.9.0.tgz",
  "_spec": "5.9.0",
  "_where": "/Users/linli/jobProjects/ionic-angular-demo",
  "author": {
    "name": "ionic"
  },
  "bugs": {
    "url": "https://github.com/ionic-team/ionic-native/issues"
  },
  "dependencies": {
    "@types/cordova": "latest"
  },
  "description": "Ionic Native - Native plugins for ionic apps",
  "homepage": "https://github.com/ionic-team/ionic-native#readme",
  "license": "MIT",
  "module": "index.js",
  "name": "@ionic-native/splash-screen",
  "peerDependencies": {
    "rxjs": "^5.5.0 || ^6.5.0",
    "@ionic-native/core": "^5.1.0"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/ionic-team/ionic-native.git"
  },
  "typings": "index.d.ts",
  "version": "5.9.0"
}

3.2 使用ths-cli腳手架生成ionic-native插件

分析完@ionic-native插件構造後咱們如今就利用腳手架來生成上面插件的結構吧!
ths-cli是本人爲公司寫的腳手架->ths-cli<- 目前只有create-ionic-native命令,能夠建立@ionic-native插件供angular項目使用,使用方法以下

// ths-cli已佔用故用ths-cli2
npm install ths-cli2 -g

使用

ths-cli create-ionic-native ths-native-toast
Usage: ths-cli <command> [項目名稱]

Options:
  -V, --version        output the version number
  -h, --help           display help for command

Commands:
  create-ionic-native  建立ionic-native插件
  help [command]       display help for command

create-ionic-native 表示建立ionic-native插件的指令

ths-native-toast 表示想要生成的插件名稱

演示,冒號後面是手動輸入的內容,其中cordova的id須要和上述cordova插件的名稱一致

ths-cli create-ionic-native ths-native-toast
> 正在下載項目模板,源地址:git@github.com:qtpalmtop/templates-ionic-native.git#master
> 插件的名稱 (ThsPlugin): ThsToast
> 插件的id (ths-native-plugin): ths-native-toast
> 插件的版本號 (1.0.0): 1.0.0 
> 對應的cordova插件的id  (cordova-plugin-ths-pluginName): cordova-plugin-ths-toast
> 插件的簡介 (A plugin named ThsPlugin): show toast
> 插件的git地址 (https://github.com/apache/cordova-plugin-ths-pluginName): https://github.com/qtpalmtop/cordova-plugin-ths-toast
正在初始化項目模板:ths-native-toast
✔ 建立成功:)


執行完後,當前目錄下將會出現建立好的ths-native-toast插件


其中ngx/index.js,能夠看出其結構已經與@ionic-native插件如出一轍,徹底能夠看成@ionic-native插件使用

發佈插件

cd ths-native-toast
npm publish

隨後在angular項目中便可經過npm install ths-native-toast, 並在app.module.ts中導入插件

4 在angular項目中調用自定義插件

app.module.ts

import { ThsToast } from 'ths-native-toast/ngx';

@NgModule({
    ...,
    providers: [
        ThsToast
    ]
})

app.component.ts

import {ThsToast} from 'ths-native-toast/ngx';

    constructor(private thsToast: ThsToast) {

    }
    
    ngOnInit() {
        this.showToast()
    }
    
    /**
    * 彈出提示
    **/
    showToast(): void {
        this.thsToast.show('hello world', () => {
            console.log('call toast success');
        }, (error) => {
            console.log('call toast error');
        });
    }

app真機運行效果


控制檯打印輸出

call toast success

5 總結

1 建立cordova插件(plugman)

2 建立ionic-native插件(ths-cli

3 angular項目中導入cordova插件和ionic-native插件

參考文章:

基於node.js的腳手架工具開發經歷

Cordova自定義插件開發

nodejs官方文檔

若有疑問或指正,歡迎在評論區留言,相逢即是緣,若是以爲本文對你有所幫助,不妨點個贊鼓勵下嘿嘿

相關文章
相關標籤/搜索