[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 及 相关资源