Как написать плагин Cordova в Swift?
Я преобразовал существующий пользовательский плагин в язык 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
то же самое, но он не работает должным образом.
Где моя проблема?
Ответы
Ответ 1
Как уже упоминалось, вы должны добавить файл моста-header.h, содержащий
#import <Cordova/CDV.h>
Также вам нужно добавить заголовок заголовка моста в свойствах проекта XCode- > Настройки сборки → Objective-C Мостовой заголовок. Например:
your-app-name/plugins/com.plugin.example/bridging-header.h
Кроме того, для того, чтобы Objective-C увидеть одно имя класса плагина, вам нужно добавить сопоставление @objc в объявление класса. Это может быть то же самое, что и название самого быстрого класса, или что-то другое. В этом примере "HWPCustomPluginInSwift" будет тем, что Objective-C (и Javascript) в конечном итоге увидит:
@objc(HWPCustomPluginInSwift) class CustomPluginInSwift : CDVPlugin {
а затем ваша функция node в файле config.xml должна выглядеть так:
<feature name="CustomPluginInSwift">
<param name="ios-package" value="HWPCustomPluginInSwift" />
</feature>
Ответ 2
CDVPlugin
не найден
Когда вы создали быстрый файл в первый раз, Xcode попросит вас сгенерировать
<your app name>-Bridging-Header.h
заголовок с пустым контентом:
//
// Use this file to import your target public headers that you would like to expose to Swift.
//
В этом заголовке добавить:
#import <Cordova/CDVPlugin.h>
После этого очистите свой проект. Если у вас нет этого заголовка - создайте его.
Класс CDVPlugin CustomPluginInSwift (pluginName: CustomPluginInSwift) не существует
[Шаг 1]
Правильно, потому что Swift использует префикс _TtC
(Type To Class) и индекс класса со следующим шаблоном:
_TtC8<AppName><index#><PluginName>
Как узнать, что такое правильный индекс?
[Шаг 2]
Когда вы запускаете экземпляр класса CustomPluginInSwift
, например:
var temp:CustomPluginInSwift = CustomPluginInSwift()
Swift добавит новое имя класса в заголовок <AppName>-Swift.h
. Проблема в том, что этот заголовок вы не видите в своем проекте.
Как его найти?
- Перейти к xCode → Окно → Органазер → "Вкладки проекта"
- Выберите свой проект
- копировать путь "Производные данные" (для меня:
~/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
[Шаг 3]
Теперь перейдите к config.xml
и измените с:
<feature name="CustomPluginInSwift">
<param name="ios-package" value="CustomPluginInSwift" />
</feature>
в
<feature name="MeeterCalendar">
<param name="ios-package" value="_TtC8Wanameet14CustomPluginInSwift" />
</feature>
Все,
Надеюсь, что это сэкономит время,
проверено на cordova 3.5
+ xCode6.1
примеры
У вас есть папка Plugins
в вашем проекте (созданная Кордовой).
Мы создаем новый быстрый файл MyPlugin.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)
})
}
, где мы возвращаем пустой callabck и через некоторое время возвращаем ответ:
Я использовал эту форму метода, когда вы пытаетесь получить некоторые данные на собственной стороне с помощью async:
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)
}
}
}