如何用Swift编写Cordova插件?

时间:2023-01-14 15:28:43

I converted existing custom plugin to Swift language:

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

(located under Plugins/CustomPluginInSwift.swift)

(在插件/ 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)
    }
}

And I have two problems:

我有两个问题:

  • CDVPlugin not found
  • CDVPlugin未找到
  • Javascript doesn't see plugin: CustomPluginInSwift:
  • Javascript没有看到插件:CustomPluginInSwift:

CDVPlugin class CustomPluginInSwift (pluginName: CustomPluginInSwift) does not exist

CDVPlugin类custompluginswift (pluginName: custompluginswift)并不存在

I left config.xml the same but it doesn't work as expected.

我配置了。xml也是一样的,但是它不能像预期的那样工作。

Where is my problem?

我的问题在哪里?

2 个解决方案

#1


22  

As is mentioned you have to add a bridging-header.h file which contains

如前所述,您必须添加一个桥接头。h文件包含

#import <Cordova/CDV.h>

Also you need to add the bridging header's path in XCode project properties->Build Settings->Objective-C Bridging Header. For example:

还需要在XCode项目属性中添加桥接头的路径—>构建设置—>Objective-C桥接头。例如:

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

Additionally, in order for Objective-C to see the same plugin class name, you need to add an @objc mapping to the class declaration. It can be the same as the swift class name itself, or something different. In this example, "HWPCustomPluginInSwift" will be what Objective-C (and Javascript) will end up seeing:

此外,为了让Objective-C看到相同的插件类名,您需要向类声明添加一个@objc映射。它可以与swift类名称本身或其他不同的名称相同。在本例中,“hwpcustompluginswift”将是Objective-C(和Javascript)最终看到的:

@objc(HWPCustomPluginInSwift) class CustomPluginInSwift : CDVPlugin {

and then your feature node in config.xml file should look like this:

然后是配置中的特性节点。xml文件应该如下所示:

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

#2


10  

CDVPlugin not found

CDVPlugin未找到

When you created swift file 1st time, Xcode asks you to generate

当您第一次创建swift文件时,Xcode要求您生成

<your app name>-Bridging-Header.h header with empty content:

<您的应用程序名称> -Bridging-Header。h页眉,内容为空:

//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//

In this header add:

在这个标题添加:

#import <Cordova/CDVPlugin.h>

After that clean your project. If you don't have this header - create it.

清理完你的项目。如果你没有这个标题-创建它。


CDVPlugin class CustomPluginInSwift (pluginName: CustomPluginInSwift) does not exist

CDVPlugin类custompluginswift (pluginName: custompluginswift)并不存在

[Step 1]

(步骤1)

Right, because Swift uses _TtC (Type To Class) prefix and class index with following template:

对,因为Swift使用_TtC (Type To Class)前缀和类索引,模板如下:

_TtC8<AppName><index#><PluginName>   

How to know what is proper index?

如何知道什么是合适的索引?

[Step 2]

(步骤2)

When you initiate instance of CustomPluginInSwift class, like:

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

var temp:CustomPluginInSwift = CustomPluginInSwift()

, Swift will add new class name to <AppName>-Swift.h header. The problem is that this header you can't see in your project.

,Swift将为 -Swift添加新的类名。h头。问题是这个标题你在你的项目中看不到。

How to find it?

如何找到它吗?

  • Go to xCode -> Window -> Organazer -> "Project Tabs"
  • 转到xCode ->窗口-> Organazer ->“项目标签”
  • Select your project
  • 选择您的项目
  • copy "Derived Data" path (for me: ~/Library/Developer/Xcode/DerivedData/<AppName>-hbgwavxfqvhwxzagxhgzjvsdrkjk)
  • 复制“派生数据”路径(对于我来说:~/Library/Developer/Xcode/DerivedData/ - hbgwggwxfqvhwxzgzjvsdrkjk)
  • Go to console and run cd ~/Library/Developer/Xcode/DerivedData/<AppName>-hbgwavxfqvhwxzagxhgzjvsdrkjk
  • 转到控制台并运行cd ~/Library/Developer/Xcode/DerivedData/ -hbgwavxfqvhwxzagxhgzjvsdrkjk
  • run after: cd Build/Intermediates/<App name>.build/Debug-iphoneos/<App name>.build/DerivedSources/
  • 运行后:cd构建/中间体/ 。构建/ Debug-iphoneos / <应用名称> .build / DerivedSources / 名称>

You can find file named: <App name>-Swift.h there with following content:

可以找到名为: -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

/* ... */

So we got proper name: _TtC8Wanameet14CustomPluginInSwift

所以我们有了正确的名字:_ttc8wanameet14custompluginswift

[Step 3]

(步骤3)

Now, go to config.xml and change from:

现在,去配置。xml和变化:

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

to:

:

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

Thats all,

这一切,

Hope it will save time,

希望它能节省时间,

tested on cordova 3.5 + xCode6.1

在cordova 3.5 + xCode6.1测试


examples

Consider you have Plugins folder in your project (generated by Cordova).

假设您的项目中有插件文件夹(由Cordova生成)。

We create New swift file MyPlugin.swift with following content:

我们创建了新的swift文件MyPlugin。迅速与以下内容:

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

method example where we parse javascript request and immediately return 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)
    })

}

method example where we return empty callabck and after some time return answer:

方法示例:返回空callabck,一段时间后返回:

I used a lot this method form when you try to fetch some data on native side by async way:

当你试图用异步方式在本地端获取数据时,我经常使用这种方法:

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)
        }
    }


}

#1


22  

As is mentioned you have to add a bridging-header.h file which contains

如前所述,您必须添加一个桥接头。h文件包含

#import <Cordova/CDV.h>

Also you need to add the bridging header's path in XCode project properties->Build Settings->Objective-C Bridging Header. For example:

还需要在XCode项目属性中添加桥接头的路径—>构建设置—>Objective-C桥接头。例如:

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

Additionally, in order for Objective-C to see the same plugin class name, you need to add an @objc mapping to the class declaration. It can be the same as the swift class name itself, or something different. In this example, "HWPCustomPluginInSwift" will be what Objective-C (and Javascript) will end up seeing:

此外,为了让Objective-C看到相同的插件类名,您需要向类声明添加一个@objc映射。它可以与swift类名称本身或其他不同的名称相同。在本例中,“hwpcustompluginswift”将是Objective-C(和Javascript)最终看到的:

@objc(HWPCustomPluginInSwift) class CustomPluginInSwift : CDVPlugin {

and then your feature node in config.xml file should look like this:

然后是配置中的特性节点。xml文件应该如下所示:

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

#2


10  

CDVPlugin not found

CDVPlugin未找到

When you created swift file 1st time, Xcode asks you to generate

当您第一次创建swift文件时,Xcode要求您生成

<your app name>-Bridging-Header.h header with empty content:

<您的应用程序名称> -Bridging-Header。h页眉,内容为空:

//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//

In this header add:

在这个标题添加:

#import <Cordova/CDVPlugin.h>

After that clean your project. If you don't have this header - create it.

清理完你的项目。如果你没有这个标题-创建它。


CDVPlugin class CustomPluginInSwift (pluginName: CustomPluginInSwift) does not exist

CDVPlugin类custompluginswift (pluginName: custompluginswift)并不存在

[Step 1]

(步骤1)

Right, because Swift uses _TtC (Type To Class) prefix and class index with following template:

对,因为Swift使用_TtC (Type To Class)前缀和类索引,模板如下:

_TtC8<AppName><index#><PluginName>   

How to know what is proper index?

如何知道什么是合适的索引?

[Step 2]

(步骤2)

When you initiate instance of CustomPluginInSwift class, like:

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

var temp:CustomPluginInSwift = CustomPluginInSwift()

, Swift will add new class name to <AppName>-Swift.h header. The problem is that this header you can't see in your project.

,Swift将为 -Swift添加新的类名。h头。问题是这个标题你在你的项目中看不到。

How to find it?

如何找到它吗?

  • Go to xCode -> Window -> Organazer -> "Project Tabs"
  • 转到xCode ->窗口-> Organazer ->“项目标签”
  • Select your project
  • 选择您的项目
  • copy "Derived Data" path (for me: ~/Library/Developer/Xcode/DerivedData/<AppName>-hbgwavxfqvhwxzagxhgzjvsdrkjk)
  • 复制“派生数据”路径(对于我来说:~/Library/Developer/Xcode/DerivedData/ - hbgwggwxfqvhwxzgzjvsdrkjk)
  • Go to console and run cd ~/Library/Developer/Xcode/DerivedData/<AppName>-hbgwavxfqvhwxzagxhgzjvsdrkjk
  • 转到控制台并运行cd ~/Library/Developer/Xcode/DerivedData/ -hbgwavxfqvhwxzagxhgzjvsdrkjk
  • run after: cd Build/Intermediates/<App name>.build/Debug-iphoneos/<App name>.build/DerivedSources/
  • 运行后:cd构建/中间体/ 。构建/ Debug-iphoneos / <应用名称> .build / DerivedSources / 名称>

You can find file named: <App name>-Swift.h there with following content:

可以找到名为: -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

/* ... */

So we got proper name: _TtC8Wanameet14CustomPluginInSwift

所以我们有了正确的名字:_ttc8wanameet14custompluginswift

[Step 3]

(步骤3)

Now, go to config.xml and change from:

现在,去配置。xml和变化:

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

to:

:

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

Thats all,

这一切,

Hope it will save time,

希望它能节省时间,

tested on cordova 3.5 + xCode6.1

在cordova 3.5 + xCode6.1测试


examples

Consider you have Plugins folder in your project (generated by Cordova).

假设您的项目中有插件文件夹(由Cordova生成)。

We create New swift file MyPlugin.swift with following content:

我们创建了新的swift文件MyPlugin。迅速与以下内容:

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

method example where we parse javascript request and immediately return 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)
    })

}

method example where we return empty callabck and after some time return answer:

方法示例:返回空callabck,一段时间后返回:

I used a lot this method form when you try to fetch some data on native side by async way:

当你试图用异步方式在本地端获取数据时,我经常使用这种方法:

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)
        }
    }


}