最近在开发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插件
参考文章:
若有疑问或指正,欢迎在评论区留言,相逢即是缘,若是以为本文对你有所帮助,不妨点个赞鼓励下嘿嘿