1. 程式人生 > >11、iOS開發詳解(基礎知識)

11、iOS開發詳解(基礎知識)

iOS開發詳解

本章節針對如何開發基於iOS系統的外掛進行介紹,在此之前,請閱讀Plugin Development Guide(外掛開發指南)對外掛的結構和JavaScript介面有一個大概的瞭解。
iOS外掛是以繼承至CDVPlugin類Objective-C的子類來實現的,通過JavaScript的exec函式來將service/parameter對映到Objective-C類,每一個外掛在工程根目錄下的config.xml檔案中通過標籤進行註冊。

外掛類的對映

我們通過如下的Cordova API來實現JavaScript到Objective-C的對映過程:

   exec(<successFunction
>
, <failFunction>, <service>, <action>, [<args>]);

通過這個JavaScript函式我們就可以使用JavaScript程式碼來執行Objective-C類的指定函式,並且通過args來傳遞引數。
通過config.xml中iOS平臺的標籤來指定需要的外掛,通過plugin.xml檔案來自動注入外掛到iOS平臺程式碼中去。

<featurename="LocalStorage"><paramname="ios-package"value="CDVLocalStorage"
/></feature>

標籤的name屬性用於指定plugin在JavaScript執行exec方法時service引數的值,為標籤內標籤內value對應的Objective-C類的具體函式名,args以陣列的形式傳入到Objective-C函式內。的name欄位永遠為’ios-package’。

外掛的例項化和生命週期

plugin物件的生命週期和UIWebView是一致的,Plugin是不需要例項化的,在他們第一次被呼叫的時候會自動例項化。也可以通過指定的方式來手動例項化一個plugin比如:

<featurename="Echo"><paramname="ios-package"
value="Echo" /><paramname="onload"value="true" /></feature>

當使用的時候,在程式啟動的時候會執行外掛的pluginInitialize方法來例項化一個外掛類物件。你可以通過覆蓋pluginInitialize方法的方式在程式啟動的時候為你的外掛做點什麼。
Plugin進行耗時操作的時候,比如媒體操作,監聽,或者網路狀態相關的事情,應該提供重置和取消操作來終止之前的操作或者請求。當需要轉入新的頁面或者重新整理頁面這種需要重新載入JavaScript的時候被使用。

建立一個iOS plugin

JavaScript通過config.xml配置的對映來發起一個plugin請求來執行Objective-C程式碼,但是最終的Objective-C外掛類什麼樣呢?下面就是plugin的一個方法定義:

   - (void)myMethod:(CDVInvokedUrlCommand*)command
    {
        CDVPluginResult* pluginResult = nil;
        NSString* myarg = [command.arguments objectAtIndex:0];

        if (myarg != nil) {
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
        } else {
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Arg was null"];
        }
        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
    }

更多的資訊可以檢視CDVInvokedUrlCommand.h, CDVPluginResult.h, CDVCommandDelegate.h這三個Cordova原始碼檔案。

iOS CDVPluginResult類

你可以使用CDVPluginResult類來返回各種型別的結果資訊給JavaScript的回撥函式,通過以下的方式來建立一個CDVPluginResult物件:

  + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAs...

你可以返回字串,整數,布林,陣列以及複合資料型別等,你也可以僅僅返回一個狀態資訊或者錯誤資訊,當然你也可以不返回任何資訊僅僅呼叫JavaScript端的回撥函式。
下面複雜型別的返回值的使用方法:
messageAsArrayBuffer以NSData的形式被傳送到JavaScript回撥函式,並且被轉換為ArrayBuffer型別,而ArrayBuffer在傳入到Objective-C端的時候會被轉換成NSData。
messageAsMultipart以NSArray的形式被傳入到JavaScript回撥函式,裡面包含各種型別的資料物件。通過這種方式傳送資料,裡面的資料會被序列化和反序列化,所以他可以安全的返回NSData,而不是Array/Dictionary。
Echo iOS Plugin(這篇文章對於plugin的配置在使用cordova build命令以後會被覆蓋,不建議在iOS工程直接加入檔案修改配置檔案資訊的方式新增外掛。使用獨立外掛通過plugin add的方式新增外掛比較容易維護和使用)

這個例子通過plugin.xml來向指定的iOS平臺注入資訊。

<platformname="ios"><config-filetarget="config.xml"parent="/*"><featurename="Echo"><paramname="ios-package"value="Echo" /></feature></config-file></platform>

新增Echo.h檔案和Echo.m檔案到iOS映象的資料夾的Plugins資料夾:

/********* Echo.h Cordova Plugin Header *******/#import <Cordova/CDVPlugin.h>

    @interface Echo : CDVPlugin

    - (void)echo:(CDVInvokedUrlCommand*)command;

    @end

    /********* Echo.m Cordova Plugin Implementation *******/#import "Echo.h"#import <Cordova/CDVPlugin.h>

    @implementation Echo

    - (void)echo:(CDVInvokedUrlCommand*)command
    {
        CDVPluginResult* pluginResult = nil;
        NSString* echo = [command.arguments objectAtIndex:0];

        if (echo != nil && [echo length] > 0) {
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:echo];
        } else {
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
        }

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

    @end

上面的類繼承至CDVPlugin類,在這裡,Echo外掛只有一個功能。就是返回JavaScript傳入的第一個引數內容。如果沒有傳入引數則返回錯誤,如果傳入引數,則將該引數返回。

CDVPlugin簡介

CDVPlugin類包含其他的一些方法,你可以通過重寫的方式來實現自己的行為,比如捕獲pause,resume等等。具體可以去讀CDVPlugin.h/CDVPlugin.m原始檔

Threading

我們在plugin裡面經常需要做一些耗時的操作,但是在主執行緒耗時過長,App就會被系統kill。所以通過runInBackground來進行耗時操作:

  - (void)myPluginMethod:(CDVInvokedUrlCommand*)command
    {
        // Check command.arguments here.
        [self.commandDelegate runInBackground:^{
            NSString* payload = nil;
            // Some blocking logic...
            CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload];
            // The sendPluginResult method is thread-safe.
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }];
    }

除錯plugin

使用Xcode來除錯plugin,如果除錯JavaScript程式碼,需要使用Safari在虛擬機器或者裝置上除錯。

易犯錯誤

不要忘記在config.xml新增對映資訊。