概述
介绍如何自己开发一个Cordova插件(android平台)。我们用ionic开发时,如果需要使用Android系统原生功能,Cordova插件是一个很好的选择。如果没有现成的cordova 插件,我们就需要自己开发一个。下面简单介绍一下如何开发。
cordova插件分为2大部分,js端和平台端(Android、ios等代码);js端定义了统一的接口,供ionic等web开发框架调用(用JavaScript方式)。平台端是具体功能针对不同平台的实现。(对应Android来说,就是实现具体功能的Java类,jar包等)。
详细的介绍大家参加cordova官网介绍:cordova plugin 。
大致步骤:
这里介绍一下本文的主要步骤:
- 开发一个简单的cordova plugin 。例子就采用官网的示例:EchoPlugin。
- 新建一个ionic 项目。使用流行的tabs方式(当然这是无关紧要的)。
- 将EchoPlugin安装到ionic项目。
- 在ionic项目中,利用JavaScript调用插件提供的echo接口。
- 运行项目,查看结果。
1. 创建插件
创建插件前,先简单介绍一下这个EchoPlugin,Android本地端提供了一个EchoPlugin.echo(String message, CallbackContext cbc)方法。这个方法的作用就是把message返回前台。org.apache.cordova.CallbackContext是cordova框架提供的。JS端定义了window.echo()接口,只要以web js方式调用这个接口,后台就能执行执行的功能(EchoPlugin.echo)。
1.1 创建项目EchoPlugin 框架
在硬盘里找个地方(比如d:\app),创建项目EchoPlugin,官网上也没提供Maven模板。自己手工建吧。先建项目根目录:EchoPlugin,然后在根目录里面建plugin.xml,www目录(js端啦),src\android(平台端啦)。参考一下图片:
1.2 编写js端代码(EchoPlugin.js):
window.echo = function(str, callback) {
cordova.exec(callback, function(err) {
callback('Nothing to echo.');
}, "EchoPlugin", "echo", [str]);
};
js端通过cordova.exec()方法,实现前台js代码对后台Java的调用。你可以先把项目跑成功再来看下面的废话。
根据Cordva官网介绍:Cordova.exec有五个参数,其作用分别如下:
第一个:success回调,当Android平台端函数执行成功后被调用。
第二个:error回调,当Android平台端函数执行不成功后被调用。
第三个:Java类名,用于指定Android平台被调用方法所在的Java类的类名。
第四个:Java方法名,用于指定Android平台被调用方法的method name。
第五个:字符串数组,作为参数args传递给Android Java method.
window.echo = function(str,callback) {...} 有两个参数,str、callback。他里面就调用了cordava.exec(...) .这里很明显,str传递给cordava.exec作为了第五个参数。callcack传递给cordava.exec成为了第一个参数。这都不是必须的,自己可以灵活掌握。
1.3 编辑Java端代码(EchoPlugin.java):
package org.apache.cordova.plugin;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* This class echoes a string called from JavaScript.
*/
public class EchoPlugin extends CordovaPlugin {
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if (action.equals("echo")) {
String message = args.getString(0);
this.echo(message, callbackContext);
return true;
}
return false;
}
private void echo(String message, CallbackContext callbackContext) {
if (message != null && message.length() > 0) {
callbackContext.success(message);
} else {
callbackContext.error("Expected one non-empty string argument.");
}
}
}
自定义插件需要继承CordovaPlugin 并且Override其execute方法。此外我们这个插件还需要实现echo()方法,这是js接口中指定的后台方法。使用插件的时候并不关心这些。
1.4 编写manifest文件: plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="cordova-plugin-echo" version="0.1.1">
<name>Echo</name>
<description>Cordova Echo Plugin</description>
<author>July</author>
<license>Apache 2.0</license>
<keywords>cordova,Echo</keywords>
<js-module src="www/EchoPlugin.js" name="echoPlugin">
<clobbers target="echoplugin" />
</js-module>
<platform name="android">
<config-file target="res/xml/config.xml" parent="/*">
<feature name="EchoPlugin">
<param name="android-package" value="org.apache.cordova.plugin.EchoPlugin" />
</feature>
</config-file>
<!-- Required 一些系统要求的权限,如访问网络等-->
<!-- <config-file target="AndroidManifest.xml" parent="/manifest">
<uses-permission android:name="android.permission.INTERNET" />
</config-file> -->
<source-file src="src/android/EchoPlugin.java" target-dir="src/org/apache/cordova/plugin" />
</platform>
</plugin>
这个文件的ID是插件的名字,估计发布到cordova服务器后可以通过ID就能安装插件;js-module元素描述了JavaScript接口信息;主要就是指出js文件位置啦;platform元素指定了各平台(这里只有android)代码的位置。config-file指定编译后目标平台配置文件config.xml的位置,cordova要把feature元素中的内容复制到config.xml中。source-file指定Java源码位置这里有2个位置,src源文件位置,target是ionic项目build android,编译为目标平台(android)项目后代码的位置。同样这段废话可以等项目跑成功后再看。
我们的插件开发完啦,libs目录是空的,因为这个Java类太简单啦,如果有需要可以将Jar包放在libs目录里。
下面我们新建一个ionic项目来使用这个插件。当然cordova项目,phonegap项目都能用这个插件。我的ionic系列是不会提供环境搭建教程的。第一次搭建环境推荐找梯子。
2. 创建ionic 项目。找一个比较合适的目录,cmd切换到该目录,执行下面的命令。
ionic start testEcho tabs
cd testEcho
ionic platform add android
cordova plugin add D:\app\EchoPlugin
3. 安装刚才开发的插件。
嗯刚才的最后一行代码就是安装自己开发的Echo cordova插件。
4. 在ionic项目中使用插件。
找到www\js\app.js,添加如下代码:
window.echo("echoMe",function(echoValue){
console.log("Echo Plugin called");
console.log(echoValue);
alert(echoValue == "echoMe");
});
添加位置:
// Ionic Starter App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
// 调用Echo插件
window.echo("echoMe",function(echoValue){
console.log("Echo Plugin called");
console.log(echoValue);
alert(echoValue == "echoMe");
});
});
})
...
5. 查看效果。cmd切换到ionic项目根目录,就是www目录的父目录。
ionic build android
ionic emulate android
效果图:
控制台:
6. 其他补充
这个例子很简单,但包含了开发一个插件的基本要素。但是Java 插件只是返回了一个信息,没有和Android原生程序交互。下面补充一下如何调用Android项目原生activity;比如某个项目的DemoActivity.java.
首先 把DemoActivity.java; 他的layout文件main.xml;他用到的jar包,so文件都辨识出来。一开始漏掉也没关系编译通不过会提示你缺少那些类,根据提示再补充。然后通过plugin.xml配置这些文件信息,指定文件编译后在Android项目中的位置就行了。
6.1 activity及 layout;这些文件都是原生Android项目文件,建议在Android项目中完成开发并且运行成功。然后直接复制文件到相应的目录。参加1.1项目框架。
DemoActivity.java
package com.test.demo;
import android.app.Activity;
/**
* 这里要用ionic项目编译后的R文件,包名需要自己去查询*
* %projecthomefolder%\platforms\android\build\generated\source\r\armv7\debug\ *
*/
import com.ionicframework.xxxx.R;
import ...
public class DemoActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
/** other method */
@Override
...
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true" >
<LinearLayout
android:id="@+id/Play"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
...
</ScrollView>
6.2 插件后台Java类,需集成CordovaPlugin
public class DemoPlugin extends CordovaPlugin {
private CallbackContext context;
/** Constructor */
public DemoPlugin() {
}
@Override
public boolean execute(String action,JSONArray args,CallbackContext callbackContext) throws JSONException {
this.context = callbackContext;
if("openDemoActivity".equals(action)) {
//使用Intent启动DemoActivity
Intent intent = new Intent(this.cordova.getActivity(),com.test.demo.DemoActivity.class);
if(this.cordova != null) {
this.cordova.startActivityForResult((CordovaPlugin) this, intent, 0);
return true;
}
return false;
}
return false;
}
@Override
public void onActivityResult(int requestCode,int resultCode,Intent intent) {
super.onActivityResult(requestCode,resultCode,intent);
//decide what to do by resultCode
if(resultCode == Activity.RESULT_OK) {
context.success("ok");
}
}
}
6.3 plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="cordova-plugin-hcnet" version="0.1.1">
<name>HcnetPlugin</name>
<description>Cordova HcNet Plugin</description>
<author>July</author>
<license>Apache 2.0</license>
<keywords>cordova,Hcnet</keywords>
<js-module src="www/DemoPlugin.js" name="DemoPlugin">
<clobbers target="DemoPlugin" />
</js-module>
<platform name="android">
<config-file target="res/xml/config.xml" parent="/*">
<feature name="DemoPlugin">
<param name="android-package" value="org.apache.cordova.plugin.DemoPlugin" />
</feature>
</config-file>
<!-- Required 一些系统要求的权限,如访问网络等-->
<config-file target="AndroidManifest.xml" parent="/manifest">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
</config-file>
<config-file target="AndroidManifest.xml" parent="/manifest/application">
<activity android:name="com.test.demo.DemoActivity"
android:label="@string/app_name">
</activity>
</config-file>
<source-file src="src/android/DemoPlugin.java" target-dir="src/org/apache/cordova/plugin" />
<source-file src="src/android/DemoActivity.java" target-dir="src/com/test/demo" />
<source-file src="src/android/xxx.java" target-dir="src/com/test/demo" />
<!-- 其他包里面的Java文件,target-dir写上src/包的路径 -->
<source-file src="src/android/Other.java" target-dir="src/com/xxx/xxx" />
<!-- lib目录里面的jar文件,target-dir写上libs -->
<source-file src="src/android/libs/SomeSDK.jar" target-dir="libs" />
<!-- 布局文件,target-dir写上libs -->
<source-file src="src/android/res/layout/main.xml" target-dir="res/layout" />
<source-file src="src/android/libs/armeabi/libAudioEngine.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libCpuFeatures.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libgnustl_shared.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libHCAlarm.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libHCCore.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libHCCoreDevCfg.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libHCDisplay.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libHCGeneralCfgMgr.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libHCIndustry.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libhcnetsdk.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libHCPlayBack.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libHCPreview.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libHCVoiceTalk.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libjnidispatch.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libopensslwrap.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libPlayCtrl.so" target-dir="libs/armeabi" />
<source-file src="src/android/libs/armeabi/libSystemTransform.so" target-dir="libs/armeabi" />
</platform>
</plugin>