如何用Swift编写Cordova插件?

25

我将现有的自定义插件转换为Swift语言:

(位于 Plugins/CustomPluginInSwift.swift下)

import Foundation

class CustomPluginInSwift : CDVPlugin {    

    func getSettings(command: CDVInvokedUrlCommand) {        

        println("CustomPluginInSwift :: getSettings is called")               

        var pluginResult = CDVPluginResult(status: CDVCommandStatus_OK)
        commandDelegate.sendPluginResult(pluginResult, callbackId:command.callbackId)
    }
}

我有两个问题:

  • CDVPlugin未找到
  • Javascript无法找到插件:CustomPluginInSwift

CDVPlugin类CustomPluginInSwift(pluginName:CustomPluginInSwift)不存在

我没有改变config.xml,但它不能按预期工作。

我的问题出在哪里?

2个回答

29

正如所提到的,您需要添加一个包含以下内容的桥接头文件(bridging-header.h)

#import <Cordova/CDV.h>

同时您需要在 XCode 项目属性 -> 构建设置 -> Objective-C Bridging Header 中添加桥接头文件的路径。例如:

your-app-name/plugins/com.plugin.example/bridging-header.h

此外,为了让 Objective-C 看到相同的插件类名,您需要在类声明中添加 @objc 映射。它可以与 Swift 类名相同,也可以是不同的。在本示例中,“HWPCustomPluginInSwift” 将是 Objective-C(和 Javascript)最终看到的内容:

@objc(HWPCustomPluginInSwift) class CustomPluginInSwift : CDVPlugin {

然后你在config.xml文件中的功能节点应该像这样:

<feature name="CustomPluginInSwift">
    <param name="ios-package" value="HWPCustomPluginInSwift" />
</feature>

我认为这是更好的解决方案。 - Maxim Shoustin
需要注意的是,当前的Cordova版本(4.3.0)似乎无法生成与Swift兼容的XCode项目。如果您正在使用Cordova CLI,则可能需要下载边缘版本才能使项目正确构建。请参见:https://github.com/apache/cordova-ios/pull/133 - sfridman
目前我正在使用钩子来启用xCode项目中的Swift支持 https://github.com/cowbell/cordova-plugin-geofence/blob/20de72b918c779511919f7e38d07721112d4f5c8/hooks/add_swift_support.js 。很高兴知道他们正在开发内置解决方案。 - tsubik
2
我在这里写了一篇使用最新的XCode 8.2 / Swift 3的教程,介绍如何撰写Cordova插件:https://medium.com/modus-create-front-end-development/writing-a-cordova-plugin-in-swift-3-for-ios-e314acf68a47#.1xxihldrj - Simon Prickett
请确保在您的 Swift 方法定义前面添加 @objc(getSettings:)!否则,您将不得不在 JS 中标记该操作为“getSettingsCommand”。 - bbjay

11

CDVPlugin未找到

当您第一次创建Swift文件时,Xcode会要求您生成一个名为<your app name>-Bridging-Header.h的头文件,并保留空内容:

//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//
在此标题中添加:
#import <Cordova/CDVPlugin.h>

在此之后清理您的项目。如果您没有这个头文件,请创建它。


CDVPlugin类CustomPluginInSwift(pluginName:CustomPluginInSwift)不存在

[步骤1]

没错,因为Swift使用_TtCType To Class)前缀和带有以下模板的类索引:

_TtC8<AppName><index#><PluginName>   

如何确定适当的索引?

[步骤2]

当您初始化CustomPluginInSwift类的实例时,例如:

var temp:CustomPluginInSwift = CustomPluginInSwift()

Swift将在<AppName>-Swift.h头文件中添加新类名。问题是,您无法在项目中看到这个头文件。

如何找到它?

  • 进入xCode -> 窗口 -> 组织器 -> “项目选项卡”
  • 选择您的项目
  • 复制“Derived Data”路径(对我来说:~/Library/Developer/Xcode/DerivedData/<AppName>-hbgwavxfqvhwxzagxhgzjvsdrkjk
  • 转到控制台并运行cd ~/Library/Developer/Xcode/DerivedData/<AppName>-hbgwavxfqvhwxzagxhgzjvsdrkjk
  • 然后运行:cd Build/Intermediates/<App name>.build/Debug-iphoneos/<App name>.build/DerivedSources/

您可以在那里找到名为<App name>-Swift.h的文件,其内容如下:

/* ... */

SWIFT_CLASS("_TtC8Wanameet14CustomPluginInSwift")
@interface CustomPluginInSwift : CDVPlugin
- (void)getSettings:(CDVInvokedUrlCommand *)command;
- (instancetype)initWithWebView:(UIWebView *)theWebView OBJC_DESIGNATED_INITIALIZER;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

/* ... */

所以我们得到了一个合适的名称:_TtC8Wanameet14CustomPluginInSwift

[第三步]

现在,打开config.xml并进行以下更改:

<feature name="CustomPluginInSwift">
    <param name="ios-package" value="CustomPluginInSwift" />
</feature>

发送至:

<feature name="MeeterCalendar">
    <param name="ios-package" value="_TtC8Wanameet14CustomPluginInSwift" />
</feature>

就这些了,希望能节省时间,

测试环境为 cordova 3.5xCode6.1


示例

假设您的项目中有一个名为Plugins的文件夹(由Cordova生成)。

我们创建一个名为MyPlugin.swift的新的Swift文件,并包含以下内容:

@objc(HWPMyPlugin) class MyPlugin : CDVPlugin { // see @tsubik answer
 /* ... */
}

一个解析JavaScript请求并立即返回结果的方法示例:

func someMethod(command: CDVInvokedUrlCommand){
    
    println("MyPlugin :: someMethod is called")
    
    let callbackId:String = command.callbackId
    
    var obj:AnyObject = command.arguments[0] as AnyObject!
    
    var eventStructure:AnyObject = obj["eventStructure"]
    var eventId:String = eventStructure["_id"] as AnyObject! as String        
    
    println("MyPlugin :: someMethod :: _id:  \(eventId) ")
        
    self.commandDelegate.runInBackground({
        // 'jw' is some class          
        var data:NSData = jw.toJson()
        var str:String = jw.toJsonString(data)
        
        
        var obj:JSONObject = jw.getJSONObjectFromNSData(data)
        println("sampleList as String: \(str)")
        
        var pluginResult:CDVPluginResult = CDVPluginResult(status: CDVCommandStatus_OK, messageAsDictionary: obj)
        self.commandDelegate.sendPluginResult(pluginResult, callbackId:command.callbackId)
    })

}

返回空回调并在一段时间后返回答案的示例方法:

我经常在原生端使用这种形式的方法来异步获取一些数据:

protocol AccountLoaderListenerItf {
   func onAccountsDone(data:NSData)
} 

@objc(HWPMyPlugin) class MyPlugin : CDVPlugin, AccountLoaderListenerItf { 
 
  var mCalendarAccountsCallbackContext:String?

  
func getCalendarAccounts( command: CDVInvokedUrlCommand ){
    println("MyPlugin :: getCalendarAccounts is called")
    
    self.mCalendarAccountsCallbackContext = command.callbackId
    
    self.commandDelegate.runInBackground({            
        
        var all:AccountLoaderListenerItf = self
        
        var accounts = MyAccounts(accLoader: all)
        
        accounts.populateFromCalendars()            
        
        var pluginResult:CDVPluginResult = CDVPluginResult(status:CDVCommandStatus_NO_RESULT)
        pluginResult.setKeepCallbackAsBool(true)
        self.commandDelegate.sendPluginResult(pluginResult, callbackId:command.callbackId)            
    })
} // func

 /* .... */

func onAccountsDone(data:NSData){
        if self.mCalendarAccountsCallbackContext != nil {            
            
            var list:JSONArray = WmUtils.getJSONArrayFromNSData(data) // dummy data
            var pluginResult:CDVPluginResult = CDVPluginResult(status: CDVCommandStatus_OK, messageAsArray: list)
            pluginResult.setKeepCallbackAsBool(false)
            self.commandDelegate.sendPluginResult(pluginResult, callbackId:self.mCalendarAccountsCallbackContext)
        }
    }


}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接