最近在開發angular工程的自定義插件api以實現cordova插件的調用時,發現網上的教程幾乎搜不到angular關於自定義插件api開發的文章,而後發現能夠參照@ionic-native的插件代碼結構整出來,因而就模仿着弄,搞了個簡單的腳手架,而後折騰了一個週末總算弄出來了,過程仍是有曲有折,故發文記錄分享javascript
本文將細緻講解cordova插件的建立、編寫、發佈到自定義@ionic-native/plugin的建立、發佈過程,以及自定義ionic-native的腳手架開發、發佈過程,還有angular項目中如何經過調用自定義@ionic-native/plugin來達到調取cordova插件的具體流程。html
建立以前確保安裝Cordovajava
cordova create CordovaProject io.cordova.hellocordova CordovaApp
CordovaProject 是建立應用程序的目錄名稱。 io.cordova.hellocordova 是默認的反向域值。 若是可能,您應該使用您本身的域值。 CordovaApp 是您應用的標題。
本人在jobProject下建立 CordovaProjectnode
$ cordova create CordovaProject com.ths.ll 思路提示框插件
plugman是用於安裝和卸載用於Apache Cordova項目的插件的命令行工具。
進入CordovaProject項目目錄,安裝plugmanlinux
$ cd ./CordovaProjectPlugins $ npm install -g plugman
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
添加完平臺後,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 文件,
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" } }
發佈後就能夠正常的經過cordova plugin add cordova-plugin-ths-toast在項目中經過ThsToast.show()使用,可是要在angular項目中使用還須要咱們開發自定義插件api,下面咱們開始ionic-native的api模塊開發
cd cordova-plugin-ths-toast npm login npm publish
使用過@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庫同樣的插件呢?
首先咱們安裝下@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" }
分析完@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中導入插件
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
1 建立cordova插件(plugman)2 建立ionic-native插件(ths-cli)
3 angular項目中導入cordova插件和ionic-native插件
參考文章:
若有疑問或指正,歡迎在評論區留言,相逢即是緣,若是以爲本文對你有所幫助,不妨點個贊鼓勵下嘿嘿