xcode – 如何在macOS应用程序中从app注册服务?
我正在尝试实现一个上下文菜单项,在选择文本时将在服务中显示.例如,如果我在TextEdit中选择一个单词,我希望在上下文菜单中显示一个菜单项“Do my stuff”,它会将所选单词提供给我的应用程序代码以供进一步处理.
通过谷歌搜索,我得出结论,我需要实现和注册服务.我试着跟着 根据我的理解,我能够做到以下几点: 我实现了服务对象: import Foundation import AppKit class ContextualMenuServiceProvider { func importString(_ pasteBoard: Pasteboard,userData: String,error: String) { print(">>>> in import string from service consumer") } } 我在Info.plist中为服务创建了一个条目: <key>NSServices</key> <array> <dict> <key>NSMenuItem</key> <dict> <key>default</key> <string>Import to $(PRODUCT_NAME)</string> </dict> <key>NSMessage</key> <string>importString</string> <key>NSPortName</key> <string>MyApp</string> <key>NSSendTypes</key> <array> <string>public.plain-text</string> </array> </dict> </array> 最后,我尝试在AppDelegate中注册该服务.现在文档说要使用: NSApp.setServicesProvider(encryptor) // where encryptor is an object of my ContextualMenuServiceProvider 但是,似乎NSApp没有setServicesProvider方法.我试着用: NSApp.servicesProvider = ContextualMenuServiceProvider() 但是,这似乎也不起作用. 我通过从Xcode运行应用程序来测试它,然后,在应用程序运行时,我尝试在TextEdit中选择一些文本(它不应该仅限于TextEdit,我只是以它为例),然后右键单击我正在寻找我的菜单项目.这是行不通的. 我能够找到某种类似的SO问题(例如,Creating an os x service或Howto add menu item to Mac OS Finder in Delphi XE2),但我无法从他们那里发现我做错了什么(更不用说大多数都是旧的(使用setServiceProvider),或者使用C#或Delphi等语言. 知道我的代码/方法有什么问题吗? 解决方法
好吧,看起来我犯了几个小错误,让我相信它不起作用.但是,最终我能够让它发挥作用.因此,如果您面临同样的任务,这里是Swift 3中的解决方案:
(1)您必须实现一种服务方法: import Cocoa class ServiceProvider: NSObject { let errorMessage = NSString(string: "Could not find the text for parsing.") func service(_ pasteboard: NSPasteboard,userData: String?,error: AutoreleasingUnsafeMutablePointer<NSString>) { guard let str = pasteboard.string(forType: NSStringPboardType) else { error.pointee = errorMessage return } let alert = NSAlert() alert.messageText = "Hello (str)" alert.informativeText = "Welcome in the service" alert.addButton(withTitle: "OK") alert.runModal() } } 以前我不知道的重要事情是提供服务的对象必须是NSObject的子类(它也可以是ViewController,或任何其他NSObject子类). Services API使用selector来调用它,而selector技术只能与NSObject一起使用. 此外,服务方法必须具有此声明:它需要3个参数,首先是NSPasteboard(您可以使用粘贴板,但不提供字符串方法)未标记,第二个是可选字符串标记为userData,第三个是AutoreleasingUnsafeMutablePointer< NSString>标记错误.按照这一点来获得最佳的类型安全性,同时仍然使其工作.否则,服务API将无法找到它并调用它.你可以将UnsafeRawPointers用于它的所有参数,但你不会获得任何东西. (2)在app delegate(或文档说你可以在任何地方进行,但我在这里做)你注册服务提供者: import Cocoa @NSApplicationMain class AppDelegate: NSObject,NSApplicationDelegate { @IBOutlet weak var window: NSWindow! func applicationDidFinishLaunching(_ aNotification: Notification) { NSApplication.shared().servicesProvider = ServiceProvider() NSUpdateDynamicServices() } } 它似乎也没有NSUpdateDynamicServices调用,但我想更安全而不是抱歉 – 它应该刷新系统中的服务,这样你就不必注销并登录用户来获取当前的服务版本. (3)最后,您必须配置Info.plist以宣传您的服务方法: <key>NSServices</key> <array> <dict> <key>NSMessage</key> <string>service</string> <key>NSPortName</key> <string>serviceTest</string> <key>NSMenuItem</key> <dict> <key>default</key> <string>Test hello world</string> </dict> <key>NSRestricted</key> <false/> <key>NSRequiredContext</key> <dict/> <key>NSSendTypes</key> <array> <string>NSStringPboardType</string> </array> </dict> </array> 这是Info.plist的XML源代码 – 尽管Apple建议使用他们的编辑器,但在Xcode 8.2中我无法通过编辑器添加NSRequiredContext键 – 我必须将文件作为源代码打开并手动添加.我建议直接编辑XML源代码. 您可以在Services Properties中找到有关每个键含义的文档,但我想提一些关键点.首先,您需要NSRequiredContext键 – 他们在文档中提到它,但编辑器不支持它 – 直接编辑XML并将其添加为空(就像我一样).其次,如果您正在使用NSSendTypes或NSReturnTypes并且您想使用字符串,请使用NSStringPboardType,即使它的documentation表示它已被弃用并且应该被NSPasteboardTypeString替换 – 后者将不起作用.最后,具有服务值的NSMessage键是服务方法的名称.所以我的服务提供者对象声明了以下方法: func service(_ pasteboard: NSPasteboard,error: AutoreleasingUnsafeMutablePointer<NSString>) 我在NSMessage中使用服务值.如果要更改它(例如,您需要多种服务方法),请不要忘记这两者必须匹配(Info.plist配置中的值和服务方法的名称). (4)在这种状态下应该有效.有一件事我想提一下,可能会帮助你调试.最后通过运行以下方法使用documentation中提到的方法对其进行测试: /Applications/TextEdit.app/Contents/MacOS/TextEdit -NSDebugServices com.mycompany.myapp 从终端运行此应该报告是否注册了使用提供的包的任何服务,以及是否将显示它 – 例如,在我的情况下问题是我没有提供强制性NSRequiredContext.在使用这种方法测试之后,我能够识别出服务已经安装,问题是服务API认为它应该被过滤掉.经过一些实验和谷歌搜索后,我通过添加空NSRequiredContext解决了它. 每次更改服务后,我建议退出TextEdit并再次运行它,似乎它保留了对旧服务提供者对象的引用(或类似的东西,如果我没有重新启动它,TextEdit没有注册更改). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |