- 摩刻部落 - https://www.moke.tw/wordpress -

PhoneGap Plugin(3):回傳JSON物件

基本教學 [1]中,有教大家如何撰寫最基本的 JavaScript 介面。這樣的介面是透過傳入 function 的方式來執行呼叫 plugin(插件) 成功與失敗時要做的事情。不過有時候我們呼叫原生程式,是為了取得一些系統的資訊。這種情況我們通常不會有傳入值,並且希望呼叫插件物件時,可以直接回傳內容,而不必大費周章地撰寫 function 的實作方法。另一方面,原本教大家的做法最後回傳的只有 string(字串) 或 int(數值),實際上我們還可以回傳 JSON 物件。

這篇 [2] CallbackContext 的實作細節可以看到,success 時能夠回傳的物件類型包括:String、int、byte[]、JSONObject、JSONArray,如果沒傳入參數的話,則會回傳一個 Status.OK 的狀態。

接取 JSON 物件的 JavaScript
本單元最重要的就是改寫 JavaScript 介面。首先,在第 2 行加入我們需要使用的系統物件 cordova/channel,接著在第 4 行建立監聽事件。監聽事件的名稱是我們可以自己修改的,只要和第 5、20、23 行保持一致即可。第 5 行表示我們在 cordova 專案呼叫插件時,必須等待 onCordovaPluginListener 事件觸發才能繼續執行。第 7-26 行我們宣告一個物件類別叫作 myPluginObj,並且此物件有三個屬性在 8-10 行。這裡的 this 是指物件本身,為了在 16-24 行中使用,我們在第 12 行把 this 存入 me 的變數裡。第 14 行是 cordova 的功能,它會在 myPluginObj 物件建立時自動執行,而我們要執行的是呼叫 myPluginObj 物件裡的 myFunction()。

var exec = require('cordova/exec'),
    channel = require('cordova/channel');

channel.createSticky('onCordovaPluginListener');		//建立監聽事件
channel.waitForInitialization('onCordovaPluginListener');	//等待監聽事件觸發

function myPluginObj() {	//宣告物件類別
	this.key1 = null;
	this.key2 = null;
	this.key3 = null;
	
	var me = this;
	
	channel.onCordovaReady.subscribe(function() {		//物件建立時執行

		me.myFunction(function(result) {	//successCallback
			me.key1 = result.att1;
			me.key2 = result.att2;
			me.key3 = result.att3;
			channel.onCordovaPluginListener.fire();	//觸發 onCordovaPluginListener 事件

		},function(e) {	//errorCallback
			channel.onCordovaPluginListener.fire();
		});
	});
}

myPluginObj.prototype.myFunction = function(successCallback, errorCallback) {	//替 myPluginObj 建立 myFunction()
    exec(successCallback, errorCallback, "pluginName", "myFuncInNav", []);
};

module.exports = new myPluginObj();	//指定 plugin 物件為一個 myPluginObj

在 JavaScript 可以把 function 視為物件類別(class),如果要增加額外的屬性或方法,可以使用 prototype 關鍵字 (參考 w3school [3])。所以第 28-30 行我們就是在 myPluginObj 中建立 myFunction(),建立的方式和第一篇 [1]介紹的是一樣的,只不過我們不需要傳入值,並且要指定成功與失敗時所要執行的呼叫。

因為 myFunction() 要傳入二個 function,所以我們會看到 16-24 行傳入了兩個 function。成功時回傳的 result 是 JSON,所以 17-19 行我們把 result 的內容存入 myPluginObj 的屬性裡,完成後觸發 onCordovaPluginListener 事件。如果呼叫 plugin 失敗,8-10 行的屬性維持在 null 即可,所以就不做任何動作,直接觸發 onCordovaPluginListener 事件。最後,在第 32 行我們把插件物件宣告成一個 myPluginObj 的物件。

在 PhoneGap 專案中取得 Plugin 物件值
完成上述的 JavaScript 介面後,在 PhoneGap 專案的使用方式就非常容易,只要使用"插件物件.屬性名"即可取得內容。"插件物件"的關鍵字是要看 plugin.xml 裡 clobbers 的設定,詳細設定方式請參考第一篇 [1] > plugin.xml 設定 > 第 12、13 行。

var key1 = pluginName.key1;

從 Android 回傳 JSON 物件
從 Android 原生程式回傳 JSON 物件非常容易,只要宣告一個 JSONObject 物件,設定完成後直接將物件回傳即可。完整的實作方式請參考第一篇 [1] Android 插件介面實作。

		if ("myFuncInNav".equals(action)) {
			JSONObject r = new JSONObject();

			r.put("att1", "value1");
			r.put("att2", "value2");
			r.put("att3", "value3");

			callbackContext.success(r);
		}
		return false;

從 iOS 回傳 JSON 物件
iOS 使用的 JSON 物件是 NSDictionary,所以我們需要實作 NSDictionary 物件,並且將它丟入 CDVPluginResult 回傳。

/********* CDVpluginName.m Cordova Plugin Implementation *******/
#import "CDVpluginName.h"
#import 

@implementation CDVpluginName

- (void)myFuncInNav:(CDVInvokedUrlCommand*)command
{
    NSDictionary* JSONObject = [self JSONObject];
    CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:JSONObject];

    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (NSDictionary*)JSONObject
{
    return @{
             @"att1": @"value1",
             @"att2": @"value2",
             @"att3": @"value3"
             };
}

@end

Also published on Medium [4].