PhoneGap Plugin(3):回傳JSON物件

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

這篇 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)。所以第 28-30 行我們就是在 myPluginObj 中建立 myFunction(),建立的方式和第一篇介紹的是一樣的,只不過我們不需要傳入值,並且要指定成功與失敗時所要執行的呼叫。

因為 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 的設定,詳細設定方式請參考第一篇 > plugin.xml 設定 > 第 12、13 行。

var key1 = pluginName.key1;

從 Android 回傳 JSON 物件

從 Android 原生程式回傳 JSON 物件非常容易,只要宣告一個 JSONObject 物件,設定完成後直接將物件回傳即可。完整的實作方式請參考第一篇 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 <Cordova/CDVPlugin.h>

@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