How to write Cordova plugin in Swift?

前端 未结 2 1081
不思量自难忘°
不思量自难忘° 2021-01-30 03:32

I converted existing custom plugin to Swift language:

(located under Plugins/CustomPluginInSwift.swift)

import Foundation

class Cu         


        
相关标签:
2条回答
  • 2021-01-30 04:04

    CDVPlugin not found

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

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

    //
    //  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

    [Step 1]

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

    _TtC8<AppName><index#><PluginName>   
    

    How to know what is proper index?

    [Step 2]

    When you initiate instance of CustomPluginInSwift class, like:

    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.

    How to find it?

    • Go to xCode -> Window -> Organazer -> "Project Tabs"
    • Select your project
    • copy "Derived Data" path (for me: ~/Library/Developer/Xcode/DerivedData/<AppName>-hbgwavxfqvhwxzagxhgzjvsdrkjk)
    • Go to console and run cd ~/Library/Developer/Xcode/DerivedData/<AppName>-hbgwavxfqvhwxzagxhgzjvsdrkjk
    • run after: cd Build/Intermediates/<App name>.build/Debug-iphoneos/<App name>.build/DerivedSources/

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

    /* ... */
    
    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

    [Step 3]

    Now, go to config.xml and change from:

    <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


    examples

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

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

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

    method example where we parse javascript request and immediately return answer:

    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:

    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)
            }
        }
    
    
    }
    
    0 讨论(0)
  • 2021-01-30 04:15

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

    #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:

    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:

    @objc(HWPCustomPluginInSwift) class CustomPluginInSwift : CDVPlugin {
    

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

    <feature name="CustomPluginInSwift">
        <param name="ios-package" value="HWPCustomPluginInSwift" />
    </feature>
    
    0 讨论(0)
提交回复
热议问题