[TOC]
# [iOS Plugin Development Guide](http://cordova.apache.org/docs/en/latest/guide/platforms/ios/plugin.html)
本節詳細介紹如何在iOS平臺上實現本地插件代碼。在閱讀本文之前,請參閱[插件開發指南](插件開發指南.md),了解插件的結構及其常見的JavaScript接口。本節繼續演示從Cordova webview到本機平臺并返回的 *echo* 示例插件。
iOS插件實現為擴展 `CDVPlugin` 類的Objective-C類。對于要映射到Objective-C 類的JavaScript`exec` 方法的 `service` 參數,每個插件類必須在指定的應用程序目錄的 `config.xml` 文件中注冊為 `feature` 標記。
# 插件類映射
插件的JavaScript部分使用 `cordova.exec` 方法如下:
~~~
exec(<successFunction>, <failFunction>, <service>, <action>, [<args>]);
~~~
這會將來自 `UIWebView` 的請求整理到iOS本機端,有效地調用 `service` 類上的 `action` 方法,并在 `args` 數組中傳遞參數。
在Cordova-iOS應用程序項目的 `config.xml` 文件中將插件指定為 `feature` 標記,使用 `plugin.xml` 文件自動注入此標記,如[插件開發指南](插件開發指南.md)中所述:
~~~
<feature name="LocalStorage">
<param name="ios-package" value="CDVLocalStorage" />
</feature>
~~~
`feature` 的 `name` 屬性應與您指定的JavaScript exec調用的`service` 參數相匹配。 `value`屬性應該與插件的 Objective-C類的名稱匹配。 `param` 的`name` 應始終為 `ios-package` 。如果您不遵循這些準則,插件可能會編譯,但Cordova可能仍然無法訪問它。
# 插件初始化和生命周期
在每個 `UIWebView`的生命周期中創建一個插件對象實例。除非首先通過JavaScript調用引用插件,否則不會實例化插件,除非在config.xml中將帶有`onload name`屬性的設置為“`true`”。例如,
~~~
<feature name="Echo">
<param name="ios-package" value="Echo" />
<param name="onload" value="true" />
</feature>
~~~
插件應該使用 `pluginInitialize` 方法作為啟動邏輯。
具有長時間運行請求或后臺活動(如媒體播放,偵聽器或維護內部狀態)的插件應實現 `onReset` 方法以取消這些長時間運行的請求或在這些活動之后進行清理。當 `UIWebView` 導航到新頁面或刷新(重新加載JavaScript)時,該方法運行。
# 編寫一個iOS Cordova插件
JavaScript調用會觸發對本機端的插件請求,并且相應的iOS Objective-C插件在 `config.xml` 文件中正確映射,但最終的iOS Objective-C插件類是什么樣的?使用JavaScript的 `exec` 函數調度到插件的任何內容都會傳遞到相應的插件類的 `action` 方法中。插件方法有這個簽名:
```
- (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](https://github.com/apache/cordova-ios/blob/master/CordovaLib/Classes/Public/CDVInvokedUrlCommand.h),[CDVPluginResult.h](https://github.com/apache/cordova-ios/blob/master/CordovaLib/Classes/Public/CDVPluginResult.h)和[CDVCommandDelegate.h](https://github.com/apache/cordova-ios/blob/master/CordovaLib/Classes/Public/CDVCommandDelegate.h)。
# iOS CDVPluginResult消息類型
您可以使用 `CDVPluginResult`將各種結果類型返回給JavaScript回調,使用遵循此模式的類方法:
```
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAs...
```
您可以創建String,Int,Double,Bool,Array,Dictionary,ArrayBuffer和Multipart類型。您也可以省略任何參數來發送狀態,或者返回錯誤,甚至選擇不發送任何插件結果,在這種情況下,兩個回調都不會觸發。
請注意以下復雜的返回值:
* `messageAsArrayBuffer` 期望`NSData*`并轉換為JavaScript回調中的 `ArrayBuffer`。同樣,JavaScript發送到插件的任何`ArrayBuffer`都會轉換為 `NSData*`。
* `messageAsMultipart` 需要包含任何其他受支持類型的`NSArray*`,并將整個數組作為JavaScript回調的參數發送。這樣,所有參數都會根據需要進行序列化或反序列化,因此將 `NSData*`作為 multipart 返回是安全的,而不是作為`Array`/`Dictionary`。
# Echo iOS插件示例
要匹配Application Plugins中描述的JavaScript接口的*echo*功能,請使用plugin.xml將 `feature` 規范注入本地平臺的config.xml文件:
~~~
<platform name="ios">
<config-file target="config.xml" parent="/*">
<feature name="Echo">
<param name="ios-package" value="Echo" />
</feature>
</config-file>
</platform>
~~~
然后我們將以下 `Echo.h` 和 `Echo.m` 文件添加到Cordova-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` 操作。它通過調用 `objectAtIndex` 方法獲取 `arguments` 數組的第一個參數 來取得 `echo`字符串,該參數對應于JavaScript `exec()` 函數傳入的參數。
它檢查參數以確保它不是`nil` 或空字符串,如果是,則返回具有 `ERROR` 狀態的 `PluginResult` 。如果參數通過了檢查,它將返回一個 `OK` 狀態的 `PluginResult` ,并傳入原始的 `echo`字符串。最后,它將結果發送到 `self.commandDelegate`,它在JavaScript端執行`exec`方法的成功或失敗回調。如果調用成功回調,則傳入`echo` 參數。
# iOS集成
`CDVPlugin` 類具有插件可以覆蓋的其他方法。例如,您可以捕獲 [pause](http://cordova.apache.org/docs/en/latest/cordova/events/events.html#pause) ,[resume](http://cordova.apache.org/docs/en/latest/cordova/events/events.html#resume),應用終止和`handleOpenURL`事件。有關指導,請參閱 [CDVPlugin.h](https://github.com/apache/cordova-ios/blob/master/CordovaLib/Classes/Public/CDVPlugin.h) 和 [CDVPlugin.m](https://github.com/apache/cordova-ios/blob/master/CordovaLib/Classes/Public/CDVPlugin.m) 類。
# 線程
插件方法通常在與主接口相同的線程中執行。如果你的插件需要大量的處理或者需要一個阻塞調用,你應該使用一個后臺線程。例如:
```
- (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];
}];
}
```
# 調試iOS插件
要在Objective-C端進行調試,您需要Xcode的內置調試器。對于JavaScript,您可以將Safari附加到iOS模擬器/設備中運行的應用程序。
# 常見的陷阱
* 不要忘記將插件的映射添加到config.xml。如果您忘記了,Xcode控制臺中會記錄一個錯誤。
* 不要忘記在白名單(whitelist)中添加您連接的任何主機,如[域白名單指南](http://cordova.apache.org/docs/en/latest/guide/appdev/whitelist/index.html)所述。如果您忘記了,Xcode控制臺中會記錄一個錯誤。
- PWA 概念
- Immutable
- Angular 基礎概念
- 入門參考
- Angular 更新總結
- Angular 生態系統
- Rx.js
- Ngrx
- CQRS/ES 模式
- Angular 5 詳解
- 測試
- 定義共享模塊
- 懶路由加載
- angular組件
- 雙向綁定及變化檢測
- 樣式
- ionic 3詳解
- ionic3
- ionic 插件
- Ionic 添加動畫
- Ghost-Loading
- 打包發布
- Android上架國內應用市場流程
- 總結
- 文章
- 問題合集
- Cordova
- 插件開發指南
- Android插件開發指南-官網
- IOS插件開發指南-官網
- Hooks 編寫
- 橋接技術
- ===cordova插件收集===
- 相關主題-官網
- 實戰-自定義插件流程
- UI 及 相關資源